<?php

namespace App\Classes\Modules\Accounts\Processors;

use App\Classes\Modules\Accounts\DataTransferObjects\AuthenticationCredentialsObject;
use App\Classes\Modules\Accounts\Services\AuthenticatesUser;
use App\Classes\Modules\Accounts\Services\AuthenticationRedirect;
use App\Classes\Modules\Accounts\Services\FetchesUser;
use App\Classes\Modules\Accounts\Services\GeneratesAuthenticationToken;
use App\Classes\Modules\Accounts\Standards\Rules\CanAuthenticateUser;
use Illuminate\Http\Request;

class AuthenticationProcessor
{

    /** @var CanAuthenticateUser */
    private $canAuthenticateUser;

    /** @var AuthenticatesUser */
    private $authenticatesUser;

    /** @var GeneratesAuthenticationToken */
    private $generatesAuthenticationToken;

    /** @var FetchesUser */
    private $fetchesUser;

    /** @var AuthenticationRedirect */
    private $authenticationRedirect;

    /**
     * AuthenticationProcessor constructor.
     * @param CanAuthenticateUser $canAuthenticateUser
     * @param AuthenticatesUser $authenticatesUser
     * @param GeneratesAuthenticationToken $generatesAuthenticationToken
     * @param FetchesUser $fetchesUser
     * @param AuthenticationRedirect $authenticationRedirect
     */
    public function __construct(CanAuthenticateUser $canAuthenticateUser, AuthenticatesUser $authenticatesUser, GeneratesAuthenticationToken $generatesAuthenticationToken, FetchesUser $fetchesUser, AuthenticationRedirect $authenticationRedirect)
    {
        $this->canAuthenticateUser = $canAuthenticateUser;
        $this->authenticatesUser = $authenticatesUser;
        $this->generatesAuthenticationToken = $generatesAuthenticationToken;
        $this->fetchesUser = $fetchesUser;
        $this->authenticationRedirect = $authenticationRedirect;
    }


    /**
     * @param Request $request
     * @return array
     * @throws \App\Classes\Exceptions\AccessForbiddenException
     * @throws \App\Classes\Exceptions\AccessUnauthorisedException
     * @throws \App\Classes\Exceptions\RequestValidationException
     */
    public function execute(Request $request): array {

        $object = new AuthenticationCredentialsObject($request->input('email'), $request->input('password'));

        $this->canAuthenticateUser->passes($object);

        $this->authenticatesUser->execute($object);

        $user = $this->fetchesUser->execute(['email' => $object->getEmail()]);

        return ['access_token' => $this->generatesAuthenticationToken->execute($user), 'redirect_url' => $this->authenticationRedirect->url($user)];

    }

}