<?php

namespace App\Security;

use App\Entity\User;
use App\Repository\UserRepository;
use Doctrine\ORM\EntityManagerInterface;
use KnpU\OAuth2ClientBundle\Client\ClientRegistry;
use KnpU\OAuth2ClientBundle\Security\Authenticator\OAuth2Authenticator;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\FlashBagAwareSessionInterface;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;

class KeycloakAuthenticator extends OAuth2Authenticator implements AuthenticationEntryPointInterface
{
    public function __construct(
        private ClientRegistry $clientRegistry,
        private EntityManagerInterface $em,
        private UserRepository $userRepository,
        private RouterInterface $router,
    ) {
    }

    public function supports(Request $request): ?bool
    {
        return 'connect_keycloak_check' === $request->attributes->get('_route');
    }

    public function authenticate(Request $request): Passport
    {
        $client = $this->clientRegistry->getClient('keycloak');
        $accessToken = $this->fetchAccessToken($client);

        return new SelfValidatingPassport(
            new UserBadge($accessToken->getToken(), function () use ($accessToken, $client) {
                $keycloakUser = $client->fetchUserFromToken($accessToken);
                $keycloakData = $keycloakUser->toArray();

                $keycloakId = $keycloakData['sub'];
                $email = $keycloakData['email'] ?? '';
                $firstName = $keycloakData['given_name'] ?? '';
                $lastName = $keycloakData['family_name'] ?? '';
                $groups = $keycloakData['groups'] ?? [];

                // Securite : verifier que l'email appartient au domaine @e-cosplay.fr
                if ('' === $email || !str_contains($email, '@e-cosplay.fr')) {
                    throw new AuthenticationException('Acces refuse : votre adresse email n\'appartient pas au domaine @e-cosplay.fr');
                }

                // Chercher l'utilisateur par keycloakId ou email
                $user = $this->userRepository->findOneBy(['keycloakId' => $keycloakId])
                    ?? $this->userRepository->findOneBy(['email' => $email]);

                if (null === $user) {
                    $user = new User();
                    $user->setEmail($email);
                    $user->setPassword('');
                }

                $user->setKeycloakId($keycloakId);
                $user->setFirstName($firstName);
                $user->setLastName($lastName);

                // Determiner le role selon les groupes Keycloak
                $roles = $this->resolveRoles($groups);
                $user->setRoles($roles);

                $this->em->persist($user);
                $this->em->flush();

                return $user;
            }),
        );
    }

    public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
    {
        return new RedirectResponse($this->router->generate('app_home'));
    }

    public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
    {
        $session = $request->getSession();
        if ($session instanceof FlashBagAwareSessionInterface) {
            $session->getFlashBag()->add('error', 'Echec de la connexion E-Cosplay : '.$exception->getMessage());
        }

        return new RedirectResponse($this->router->generate('app_home'));
    }

    public function start(Request $request, ?AuthenticationException $authException = null): Response
    {
        return new RedirectResponse($this->router->generate('app_home'));
    }

    /**
     * @param list<string> $groups
     *
     * @return list<string>
     */
    private function resolveRoles(array $groups): array
    {
        if (\in_array('superadmin', $groups, true) || \in_array('super_admin_asso', $groups, true)) {
            return ['ROLE_ROOT'];
        }

        if (\in_array('gp_member', $groups, true)) {
            return ['ROLE_EMPLOYE'];
        }

        return ['ROLE_USER'];
    }
}
