<?php

declare(strict_types=1);

namespace App\Tests\Unit\Administration\Infrastructure\Api\Provider;

use ApiPlatform\Metadata\Get;
use App\Administration\Application\Port\ActiveRoleStore;
use App\Administration\Application\Service\RoleContext;
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\Model\User\UserId;
use App\Administration\Domain\Repository\UserRepository;
use App\Administration\Infrastructure\Api\Provider\MyRolesProvider;
use App\Administration\Infrastructure\Security\SecurityUser;
use App\Shared\Domain\Tenant\TenantId;
use App\SuperAdmin\Domain\Model\SuperAdmin\SuperAdminId;
use App\SuperAdmin\Infrastructure\Security\SecuritySuperAdmin;
use DateTimeImmutable;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;

final class MyRolesProviderTest extends TestCase
{
    #[Test]
    public function provideReturnsSuperAdminRoleForSecuritySuperAdmin(): void
    {
        $security = $this->createMock(Security::class);
        $security->method('getUser')->willReturn(
            new SecuritySuperAdmin(
                superAdminId: SuperAdminId::generate(),
                email: 'sadmin@test.com',
                hashedPassword: 'hashed',
            )
        );

        $userRepository = $this->createMock(UserRepository::class);
        $roleContext = new RoleContext(new NullActiveRoleStore());

        $provider = new MyRolesProvider($security, $userRepository, $roleContext);
        $output = $provider->provide(new Get());

        self::assertSame('ROLE_SUPER_ADMIN', $output->activeRole);
        self::assertSame('Super Admin', $output->activeRoleLabel);
        self::assertCount(1, $output->roles);
        self::assertSame('ROLE_SUPER_ADMIN', $output->roles[0]['value']);
        self::assertSame('Super Admin', $output->roles[0]['label']);
    }

    #[Test]
    public function provideReturnsUserRolesForSecurityUser(): void
    {
        $userId = UserId::generate();
        $tenantId = TenantId::fromString('550e8400-e29b-41d4-a716-446655440002');

        $securityUser = new SecurityUser(
            userId: $userId,
            email: 'user@example.com',
            hashedPassword: 'hashed',
            tenantId: $tenantId,
            roles: ['ROLE_PARENT'],
        );

        $security = $this->createMock(Security::class);
        $security->method('getUser')->willReturn($securityUser);

        $user = User::reconstitute(
            id: $userId,
            email: new Email('user@example.com'),
            roles: [Role::PARENT],
            tenantId: $tenantId,
            schoolName: 'Test',
            statut: StatutCompte::ACTIF,
            dateNaissance: null,
            createdAt: new DateTimeImmutable(),
            hashedPassword: 'hashed',
            activatedAt: new DateTimeImmutable(),
            consentementParental: null,
        );

        $userRepository = $this->createMock(UserRepository::class);
        $userRepository->method('get')->willReturn($user);

        $roleContext = new RoleContext(new NullActiveRoleStore());

        $provider = new MyRolesProvider($security, $userRepository, $roleContext);
        $output = $provider->provide(new Get());

        self::assertSame('ROLE_PARENT', $output->activeRole);
    }

    #[Test]
    public function provideThrowsUnauthorizedForUnknownUserType(): void
    {
        $security = $this->createMock(Security::class);
        $security->method('getUser')->willReturn(null);

        $userRepository = $this->createMock(UserRepository::class);
        $roleContext = new RoleContext(new NullActiveRoleStore());

        $provider = new MyRolesProvider($security, $userRepository, $roleContext);

        $this->expectException(UnauthorizedHttpException::class);
        $provider->provide(new Get());
    }
}

/**
 * @internal
 */
final class NullActiveRoleStore implements ActiveRoleStore
{
    public function store(User $user, Role $role): void
    {
    }

    public function get(User $user): ?Role
    {
        return null;
    }

    public function clear(User $user): void
    {
    }
}
