<?php

declare(strict_types=1);

namespace App\Administration\Infrastructure\Api\Processor;

use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface;
use App\Administration\Application\Command\ResetPassword\ResetPasswordCommand;
use App\Administration\Application\Command\ResetPassword\ResetPasswordHandler;
use App\Administration\Domain\Exception\PasswordResetTokenAlreadyUsedException;
use App\Administration\Domain\Exception\PasswordResetTokenExpiredException;
use App\Administration\Domain\Exception\PasswordResetTokenNotFoundException;
use App\Administration\Domain\Exception\TokenConsumptionInProgressException;
use App\Administration\Infrastructure\Api\Resource\ResetPasswordInput;
use App\Administration\Infrastructure\Api\Resource\ResetPasswordOutput;
use Override;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\ConflictHttpException;
use Symfony\Component\HttpKernel\Exception\GoneHttpException;

/**
 * API Platform processor for password reset.
 *
 * Handles errors:
 * - Token not found → 400 Bad Request
 * - Token expired → 410 Gone
 * - Token already used → 410 Gone
 * - Concurrent consumption → 409 Conflict (client should retry)
 *
 * @implements ProcessorInterface<ResetPasswordInput, ResetPasswordOutput>
 */
final readonly class ResetPasswordProcessor implements ProcessorInterface
{
    public function __construct(
        private ResetPasswordHandler $handler,
    ) {
    }

    /**
     * @param ResetPasswordInput $data
     */
    #[Override]
    public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): ResetPasswordOutput
    {
        $command = new ResetPasswordCommand(
            token: $data->token,
            newPassword: $data->password,
        );

        try {
            ($this->handler)($command);
        } catch (PasswordResetTokenNotFoundException) {
            throw new BadRequestHttpException('Le lien de réinitialisation est invalide.');
        } catch (PasswordResetTokenExpiredException) {
            throw new GoneHttpException('Le lien de réinitialisation a expiré. Veuillez faire une nouvelle demande.');
        } catch (PasswordResetTokenAlreadyUsedException) {
            throw new GoneHttpException('Ce lien a déjà été utilisé. Veuillez faire une nouvelle demande si nécessaire.');
        } catch (TokenConsumptionInProgressException) {
            throw new ConflictHttpException('Requête en cours de traitement. Veuillez réessayer.');
        }

        return new ResetPasswordOutput();
    }
}
