<?php

namespace apexl\Io\modules\user\controllers;

use apexl\Io\exceptions\RecordNotFoundException;
use apexl\Io\factories\RequestHelperFactory;
use apexl\Io\includes\Controller;
use apexl\Io\modules\user\Actions\RefreshAction;
use apexl\Io\modules\user\exceptions\ClientCredentialsValidationException;
use apexl\Io\modules\user\exceptions\RefreshTokenExpiredException;
use apexl\Io\modules\user\exceptions\RefreshTokenUserMismatchException;
use apexl\Io\modules\user\RequestHelper\RefreshRequestHelper;
use apexl\Io\modules\user\services\RefreshTokenEntityFinder;
use apexl\Io\modules\user\services\RefreshTokenSessionIdFinder;
use Exception;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

final readonly class RefreshController extends Controller
{
    public function __invoke(
        RequestHelperFactory $requestHelperFactory,
        RefreshAction $refreshAction,
        RefreshTokenSessionIdFinder $sessionIdFinder,
        RefreshTokenEntityFinder $refreshTokenEntityFinder,
        RefreshTokenSessionIdFinder $refreshTokenSessionIdFinder,
        ServerRequestInterface $request,
        ResponseInterface $response,
    ): ResponseInterface {
        try {
            $requestHelper = $requestHelperFactory->make(RefreshRequestHelper::class, $request);

            $refreshTokenEntity = $refreshTokenEntityFinder->fromToken($requestHelper->refreshToken());
            $sessionId = $refreshTokenSessionIdFinder->find($request, $refreshTokenEntity);

            $newAuthToken = $refreshAction->handle($requestHelper->refreshToken(), $sessionId);

            $this->output->addResponse($request, ['access_token' => $newAuthToken]);

            return $this->json($response);
        } catch (
        ClientCredentialsValidationException|
        RefreshTokenUserMismatchException|
        RefreshTokenExpiredException
        $exception
        ) {
            return $this->json(
                $response,
                ['error' => $exception->getMessage()],
                401,
            );
        } catch (RecordNotFoundException $exception) {
            return $this->json(
                $response,
                ['error' => $exception->getMessage()],
                404,
            );
        } catch (Exception $exception) {
            return $this->json(
                $response,
                ['error' => $exception->getMessage()],
                500,
            );
        }
    }

}
