<?php

declare(strict_types=1);

namespace apexl\Io\modules\user\controllers;

use apexl\Io\exceptions\RecordNotFoundException;
use apexl\Io\includes\Controller;
use apexl\Io\modules\user\Actions\RefreshAction;
use apexl\Io\modules\user\exceptions\RefreshTokenExpiredException;
use apexl\Io\modules\user\exceptions\RefreshTokenUserMismatchException;
use apexl\Io\modules\user\Request\RefreshRequest;
use apexl\Io\modules\user\services\RefreshTokenEntityFinder;
use apexl\Io\modules\user\services\RefreshTokenSessionIdFinder;
use Exception;
use JsonException;
use Psr\Http\Message\ResponseInterface;

final readonly class RefreshController extends Controller
{
    /**
     * @throws JsonException
     */
    public function __invoke(
        RefreshRequest $request,
        ResponseInterface $response,
        RefreshAction $refreshAction,
        RefreshTokenSessionIdFinder $sessionIdFinder,
        RefreshTokenEntityFinder $refreshTokenEntityFinder,
        RefreshTokenSessionIdFinder $refreshTokenSessionIdFinder,
    ): ResponseInterface {
        try {
            $refreshTokenEntity = $refreshTokenEntityFinder->fromToken($request->refreshToken());
            $sessionId = $refreshTokenSessionIdFinder->find($request, $refreshTokenEntity);

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

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

            return $this->json($response);
        } catch (
        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,
            );
        }
    }

}
