<?php

namespace Google\Auth\tests;

use Google\Auth\Credentials\AppIdentityCredentials;
use Google\Auth\Credentials\GCECredentials;
use Google\Auth\Credentials\ServiceAccountCredentials;
use Google\Auth\Credentials\ServiceAccountJwtAccessCredentials;
use Google\Auth\Credentials\UserRefreshCredentials;
use Google\Auth\CredentialsLoader;
use Google\Auth\FetchAuthTokenInterface;
use Google\Auth\OAuth2;

class FetchAuthTokenTest extends BaseTest
{
    /** @dataProvider provideAuthTokenFetcher */
    public function testGetLastReceivedToken(FetchAuthTokenInterface $fetcher)
    {
        $accessToken = $fetcher->getLastReceivedToken();

        $this->assertNotNull($accessToken);
        $this->assertArrayHasKey('access_token', $accessToken);
        $this->assertArrayHasKey('expires_at', $accessToken);

        $this->assertEquals('xyz', $accessToken['access_token']);
        $this->assertEquals(strtotime('2001'), $accessToken['expires_at']);
    }

    public function provideAuthTokenFetcher()
    {
        $scopes = ['https://www.googleapis.com/auth/drive.readonly'];
        $jsonPath = sprintf(
            '%s/fixtures/.config/%s',
            __DIR__,
            CredentialsLoader::WELL_KNOWN_PATH
        );
        $jsonPath2 = sprintf(
            '%s/fixtures2/.config/%s',
            __DIR__,
            CredentialsLoader::WELL_KNOWN_PATH
        );

        return [
            [$this->getAppIdentityCredentials()],
            [$this->getGCECredentials()],
            [$this->getServiceAccountCredentials($scopes, $jsonPath)],
            [$this->getServiceAccountJwtAccessCredentials($jsonPath)],
            [$this->getUserRefreshCredentials($scopes, $jsonPath2)],
            [$this->getOAuth2()],
        ];
    }

    private function getAppIdentityCredentials()
    {
        $class = new \ReflectionClass(
            'Google\Auth\Credentials\AppIdentityCredentials'
        );
        $property = $class->getProperty('lastReceivedToken');
        $property->setAccessible(true);

        $credentials = new AppIdentityCredentials();
        $property->setValue($credentials, [
            'access_token' => 'xyz',
            'expiration_time' => strtotime('2001'),
        ]);

        return $credentials;
    }

    private function getGCECredentials()
    {
        $class = new \ReflectionClass(
            'Google\Auth\Credentials\GCECredentials'
        );
        $property = $class->getProperty('lastReceivedToken');
        $property->setAccessible(true);

        $credentials = new GCECredentials();
        $property->setValue($credentials, [
            'access_token' => 'xyz',
            'expires_at' => strtotime('2001'),
        ]);

        return $credentials;
    }

    private function getServiceAccountCredentials($scopes, $jsonPath)
    {
        $class = new \ReflectionClass(
            'Google\Auth\Credentials\ServiceAccountCredentials'
        );
        $property = $class->getProperty('auth');
        $property->setAccessible(true);

        $credentials = new ServiceAccountCredentials($scopes, $jsonPath);
        $property->setValue($credentials, $this->getOAuth2Mock());

        return $credentials;
    }

    private function getServiceAccountJwtAccessCredentials($jsonPath)
    {
        $class = new \ReflectionClass(
            'Google\Auth\Credentials\ServiceAccountJwtAccessCredentials'
        );
        $property = $class->getProperty('auth');
        $property->setAccessible(true);

        $credentials = new ServiceAccountJwtAccessCredentials($jsonPath);
        $property->setValue($credentials, $this->getOAuth2Mock());

        return $credentials;
    }

    private function getUserRefreshCredentials($scopes, $jsonPath)
    {
        $class = new \ReflectionClass(
            'Google\Auth\Credentials\UserRefreshCredentials'
        );
        $property = $class->getProperty('auth');
        $property->setAccessible(true);

        $credentials = new UserRefreshCredentials($scopes, $jsonPath);
        $property->setValue($credentials, $this->getOAuth2Mock());

        return $credentials;
    }

    private function getOAuth2()
    {
        $oauth = new OAuth2([
            'access_token' => 'xyz',
            'expires_at' => strtotime('2001'),
        ]);

        return $oauth;
    }

    private function getOAuth2Mock()
    {
        $mock = $this->getMockBuilder('Google\Auth\OAuth2')
            ->disableOriginalConstructor()
            ->getMock();

        $mock
            ->expects($this->once())
            ->method('getLastReceivedToken')
            ->will($this->returnValue([
                'access_token' => 'xyz',
                'expires_at' => strtotime('2001'),
            ]));

        return $mock;
    }
}
