<?php

namespace AuthStack\OAuth2\Model\Protocol\Grant\tests\units;

use mageekguy\atoum;
use Illuminate\Http\Request;
use AuthStack\OAuth2\Exception\OAuth2Exception;
use AuthStack\OAuth2\Model\Protocol\Grant\GrantFactory;
use AuthStack\OAuth2\Model\Protocol\Request\PasswordCredentials\GrantRequest;
use AuthStack\OAuth2\Model\Protocol\Response\PasswordCredentials\GrantResponse;

class PasswordCredentials extends atoum\test
{
    public function testCreatePasswordCredentialsRequest()
    {
        $this->given($pwdcred = (new GrantFactory())->passwordCredentials()->grantRequest())
            ->then
                ->object($pwdcred)->isInstanceOf(GrantRequest::class)
                ->object(
                    $pwdcred
                        ->setUsername('dyson.frost@mail.com')
                        ->setPassword('bad_password')
                        ->setScope('read write')
                )
                ->isInstanceOf(GrantRequest::class)
                ->array($pwdcred->toArray())
                    ->hasKeys(['grant_type', 'username', 'password', 'scope'])
                    ->strictlyContainsValues([
                        'grant_type' => 'password',
                        'username' => 'dyson.frost@mail.com',
                        'password' => 'bad_password',
                        'scope' => 'read write'
                    ])
            ;
    }

    public function testReceivePasswordCredentialsRequest()
    {
        $this->given($model = [
            'grant_type' => 'password',
            'username' => 'dyson.frost@mail.com',
            'password' => 'bad_password',
            'scope' => 'read write'
        ])
            ->and($request = Request::create('https://your.authorization.server/access_token', 'GET', $model))
            ->then
                ->object($pwdcred = (new GrantFactory())->passwordCredentials()->grantRequest()->receive($request))->isInstanceOf(GrantRequest::class)
                ->array($pwdcred->toArray())
                    ->hasKeys(['grant_type', 'username', 'password', 'scope'])
                    ->strictlyContainsValues([
                        'grant_type' => 'password',
                        'username' => 'dyson.frost@mail.com',
                        'password' => 'bad_password',
                        'scope' => 'read write'
                    ])
            ;
    }

    public function testReceivePasswordCredentialsRequestFails()
    {
        $this->given($model = [
            'grant_type' => 'password2', // <- this is wrong, as it must be 'password'
            'username' => 'dyson.frost@mail.com',
            'password' => 'bad_password',
            'scope' => 'read write'
        ])
            ->and($request = Request::create('https://your.authorization.server/access_token', 'GET', $model))
            ->then
                ->exception(function() use ($request)
                {
                    $pwdcred = (new GrantFactory())->passwordCredentials()->grantRequest()->receive($request);
                })->isInstanceOf(OAuth2Exception::class)
            ;
    }

    public function testCreatePasswordCredentialsResponse()
    {
        $this->given($pwd = (new GrantFactory())->passwordCredentials()->grantResponse())
            ->then
                ->object($pwd)->isInstanceOf(GrantResponse::class)
                ->object(
                    $pwd
                        ->setAccessToken('this_is_access_token')
                        ->setTokenType('bearer')
                        ->setExpiresIn(300)
                        ->setRefreshToken('this_is_refresh_token')
                )->isInstanceOf(GrantResponse::class)
                ->array($pwd->toArray())
                    ->hasKeys(['access_token', 'token_type', 'expires_in', 'refresh_token'])
                    ->strictlyContainsValues([
                        'access_token' => 'this_is_access_token',
                        'token_type' => 'bearer',
                        'expires_in' => 300,
                        'refresh_token' => 'this_is_refresh_token'
                    ])
            ;
    }

    public function testReceivePasswordCredentialsResponse()
    {
        $this->given($model = [
            'access_token' => 'hi',
            'token_type' => 'bearer',
            'expires_in' => 200,
            'refresh_token' => 'refresh_me'
        ])
            ->and($request = Request::create('https://your.relying.party/callback', 'GET', $model))
            ->then
                /** @var $resp GrantResponse */
                ->object($resp = (new GrantFactory())->passwordCredentials()->grantResponse()->receive($request))->isInstanceOf(GrantResponse::class)
                ->string($resp->getAccessToken())->isEqualTo('hi')
                ->string($resp->getTokenType())->isEqualTo('bearer')
                ->integer($resp->getExpiresIn())->isEqualTo(200)
                ->string($resp->getRefreshToken())->isEqualTo('refresh_me')
            ;
    }
}