<?php

namespace AuthStack\OAuth2\Model\Protocol\Request\AuthorizationCode;

use AuthStack\OAuth2\Exception\OAuth2Exception;
use AuthStack\OAuth2\Model\Protocol\Request\AbstractRequest;
use AuthStack\OAuth2\OAuth2Constants;
use Illuminate\Http\Request;

class TokenRequest extends AbstractRequest
{
    /**
     * Returns the following array:
     *
     * @return array
     */
    public function toArray(): array
    {
        // Removes empty values (and keys) and returns the resulting array
        $collection = collect($this->model)
            ->reject(function($value, $item) {
                return empty($value);
            })
            ->put('grant_type', $this->getGrantType());

        return $collection->toArray();
    }

    public function model(): array
    {
        return [
            'client_id', 'client_secret', 'grant_type', 'code', 'redirect_uri'
        ];
    }

    /**
     * @param Request|null $request
     * @return AbstractRequest
     * @throws OAuth2Exception
     * @return TokenRequest
     */
    public function receive(Request $request = null): self
    {
        $request = $request ?? $request::createFromGlobals();

        $collection = collect();

        collect($this->model())->map(function($value) use ($request, $collection)
        {
            $collection->put($value, $request->input($value));
        });

        if($collection->get('grant_type') !== $this->getGrantType())
        {
            throw new OAuth2Exception(OAuth2Constants::ERR_INVALID_REQUEST);
        }

        return $this->setModel($collection->toArray());
    }

    /**
     * @return string
     */
    public function getGrantType(): string
    {
        return OAuth2Constants::GRANT_TYPE_AUTH_CODE;
    }

    public function getClientID()
    {
        return $this->getProperty('client_id');
    }

    public function getClientSecret()
    {
        return $this->getProperty('client_secret');
    }

    public function getCode()
    {
        return $this->getProperty('code');
    }

    public function getRedirectURI()
    {
        return $this->getProperty('redirect_uri');
    }

    /**
     * @param string $secret
     * @return $this
     */
    public function setClientSecret(string $secret): self
    {
        return $this->setProperty('client_secret', $secret);
    }

    /**
     * @param string $code
     * @return $this
     */
    public function setCode(string $code): self
    {
        return $this->setProperty('code', $code);
    }

}