<?php

declare(strict_types=1);

namespace App\Administration\Infrastructure\Console;

use App\Administration\Domain\Model\PasswordResetToken\PasswordResetToken;
use App\Administration\Domain\Model\User\Email;
use App\Administration\Domain\Model\User\Role;
use App\Administration\Domain\Model\User\StatutCompte;
use App\Administration\Domain\Model\User\User;
use App\Administration\Domain\Policy\ConsentementParentalPolicy;
use App\Administration\Domain\Repository\PasswordResetTokenRepository;
use App\Administration\Domain\Repository\UserRepository;
use App\Administration\Infrastructure\Security\SecurityUser;
use App\Shared\Domain\Clock;
use App\Shared\Infrastructure\Tenant\TenantNotFoundException;
use App\Shared\Infrastructure\Tenant\TenantRegistry;

use function sprintf;

use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;

/**
 * Creates a test user with an activated account and a password reset token.
 *
 * This command is for E2E testing only. It creates:
 * - An activated user (so they can use the reset password flow)
 * - A password reset token for that user
 */
#[AsCommand(
    name: 'app:dev:create-test-password-reset-token',
    description: 'Creates a test user and password reset token for E2E testing',
)]
final class CreateTestPasswordResetTokenCommand extends Command
{
    public function __construct(
        private readonly PasswordResetTokenRepository $passwordResetTokenRepository,
        private readonly UserRepository $userRepository,
        private readonly UserPasswordHasherInterface $passwordHasher,
        private readonly TenantRegistry $tenantRegistry,
        private readonly ConsentementParentalPolicy $consentementPolicy,
        private readonly Clock $clock,
    ) {
        parent::__construct();
    }

    protected function configure(): void
    {
        $this
            ->addOption('email', null, InputOption::VALUE_OPTIONAL, 'Email address', 'reset-test@example.com')
            ->addOption('tenant', null, InputOption::VALUE_OPTIONAL, 'Tenant subdomain', 'ecole-alpha')
            ->addOption('base-url', null, InputOption::VALUE_OPTIONAL, 'Frontend base URL', 'http://localhost:5174')
            ->addOption('expired', null, InputOption::VALUE_NONE, 'Create an expired token (for testing expired flow)');
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = new SymfonyStyle($input, $output);

        /** @var non-empty-string $email */
        $email = $input->getOption('email');
        /** @var string $tenantSubdomain */
        $tenantSubdomain = $input->getOption('tenant');
        /** @var string $baseUrlOption */
        $baseUrlOption = $input->getOption('base-url');
        $baseUrl = rtrim($baseUrlOption, '/');
        $expired = $input->getOption('expired');

        // Resolve tenant
        try {
            $tenantConfig = $this->tenantRegistry->getBySubdomain($tenantSubdomain);
            $tenantId = $tenantConfig->tenantId;
        } catch (TenantNotFoundException) {
            $io->error(sprintf('Tenant "%s" not found.', $tenantSubdomain));

            return Command::FAILURE;
        }

        $now = $this->clock->now();

        // Check if user already exists
        $user = $this->userRepository->findByEmail(new Email($email), $tenantId);

        if ($user === null) {
            // Create an activated user (password reset requires an existing activated account)
            $user = User::creer(
                email: new Email($email),
                role: Role::PARENT,
                tenantId: $tenantId,
                schoolName: 'École de Test E2E',
                dateNaissance: null,
                createdAt: $now,
            );

            // Create SecurityUser adapter for password hashing
            $securityUser = new SecurityUser(
                userId: $user->id,
                email: $email,
                hashedPassword: '',
                tenantId: $tenantId,
                roles: [$user->role->value],
            );

            // Activate the user with a password
            $hashedPassword = $this->passwordHasher->hashPassword($securityUser, 'OldPassword123!');
            $user->activer($hashedPassword, $now, $this->consentementPolicy);

            $this->userRepository->save($user);
            $io->note('Created new activated user');
        } elseif ($user->statut !== StatutCompte::ACTIF) {
            // Create SecurityUser adapter for password hashing
            $securityUser = new SecurityUser(
                userId: $user->id,
                email: $email,
                hashedPassword: '',
                tenantId: $tenantId,
                roles: [$user->role->value],
            );

            // Activate existing user if not active
            $hashedPassword = $this->passwordHasher->hashPassword($securityUser, 'OldPassword123!');
            $user->activer($hashedPassword, $now, $this->consentementPolicy);
            $this->userRepository->save($user);
            $io->note('Activated existing user');
        }

        // Create password reset token
        $createdAt = $expired
            ? $now->modify('-2 hours') // Expired: created 2 hours ago (tokens expire after 1 hour)
            : $now;

        $token = PasswordResetToken::generate(
            userId: (string) $user->id,
            email: $email,
            tenantId: $tenantId,
            createdAt: $createdAt,
        );

        $this->passwordResetTokenRepository->save($token);

        $resetUrl = sprintf('%s/reset-password/%s', $baseUrl, $token->tokenValue);

        $io->success('Test password reset token created!');

        $io->table(
            ['Property', 'Value'],
            [
                ['User ID', (string) $user->id],
                ['Email', $email],
                ['Tenant', $tenantSubdomain],
                ['Token', $token->tokenValue],
                ['Created', $token->createdAt->format('Y-m-d H:i:s')],
                ['Expires', $token->expiresAt->format('Y-m-d H:i:s')],
                ['Expired', $expired ? 'Yes' : 'No'],
            ]
        );

        $io->writeln('');
        $io->writeln(sprintf('<info>Reset URL:</info> <href=%s>%s</>', $resetUrl, $resetUrl));
        $io->writeln('');

        return Command::SUCCESS;
    }
}
