<?php 
// src/Security/KeycloakAuthenticator.php
namespace App\Security;

use App\Entity\User;
use App\Entity\Gamemaster;
use Doctrine\ORM\EntityManagerInterface;
use KnpU\OAuth2ClientBundle\Client\ClientRegistry;
use League\OAuth2\Client\Provider\ResourceOwnerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\String\Slugger\AsciiSlugger;

class KeycloakAuthenticator extends AbstractAuthenticator
{
    public function __construct(
        private ClientRegistry $clientRegistry,
        private EntityManagerInterface $em,
        private UserPasswordHasherInterface $hasher,
        private UrlGeneratorInterface $urlGenerator
    ) {}

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

    public function authenticate(Request $request): SelfValidatingPassport
    {
        
        $client = $this->clientRegistry->getClient('keycloak');
        $accessToken = $client->getAccessToken();
        $keycloakUser = $client->fetchUserFromToken($accessToken);
        $data = $keycloakUser->toArray();
        $email = $data['email'] ?? null;

        return new SelfValidatingPassport(
            new UserBadge($email, function($email) use ($data) {
                $user = $this->em->getRepository(User::class)->findOneBy(['email' => $email]);

                if (!$user) {
                    $user = new User();
                    $user->setEmail($email);
                    $user->setFirstName($data['given_name'] ?? '');
                    $user->setLastName($data['family_name'] ?? '');
                    $user->setPhone($data['phone_number'] ?? '');
                    $user->setRoles(['ROLE_USER']);
                    $user->setIsVerified(true);
                    $user->setPassword(
                        $this->hasher->hashPassword($user, bin2hex(random_bytes(10)))
                    );
                    $this->em->persist($user);
                } else {
                    // Il vient de KC, donc, l'email est fiabilisé
                    $user->setIsVerified(true);
                    // Mise à jour du numéro de téléphone s'il est renseigné dans KC
                    $user->setPhone($data['phone_number'] ?? $user->getPhone());
                    $user->setFirstName($data['given_name'] ?? $user->getFirstName());
                    $user->setLastName($data['family_name'] ?? $user->getLastName());
                }
                
                // Mise à jour des rôle et du profil GM
                if (in_array($_ENV['KEYCLOAK_ADMIN_GROUP'], $data['groups'])) {
                    $user->setRoles(['ROLE_ADMIN']);
                } elseif (in_array($_ENV['KEYCLOAK_MANAGER_GROUP'], $data['groups'])) {
                    $user->setRoles(['ROLE_MANAGER']);
                } elseif (in_array($_ENV['KEYCLOAK_STAFF_GROUP'], $data['groups'])) {
                    $user->setRoles(['ROLE_STAFF']);
                }
                
                if (in_array($_ENV['KEYCLOAK_GAMEMASTER_GROUP'], $data['groups'])) {
                    if (!$user->getLinkToGamemaster()) {
                        // Créer un profil MJ
                        $gamemaster = new Gamemaster();
                        $gamemaster->setFirstName($user->getFirstName());
                        $gamemaster->setLastName($user->getLastName());
                        $gamemaster->setPreferedName($data['nickname']);
                        $slugger = new AsciiSlugger('fr_FR');
                        $slug = $slugger->slug(strtolower($data['nickname']));
                        $gamemaster->setSlug($slug);
                        $gamemaster->setEmail($user->getEmail());
                        $phone = $user->getPhone();
                        if ($phone) { $gamemaster->setPhone($phone); }
                        $gamemaster->setLinkToUser($user);
                        $this->em->persist($gamemaster);    
                    } else {
                        // Mettre à jour le profil MJ
                        $gamemaster = $user->getLinkToGamemaster();
                        $gamemaster->setFirstName($user->getFirstName());
                        $gamemaster->setLastName($user->getLastName());
                        $gamemaster->setPreferedName($data['nickname']);
                        $slugger = new AsciiSlugger('fr_FR');
                        $slug = $slugger->slug(strtolower($data['nickname']));
                        $gamemaster->setSlug($slug);
                        $gamemaster->setEmail($user->getEmail());
                        $phone = $user->getPhone();
                        if ($phone) { $gamemaster->setPhone($phone); }
                    }
                }

                $this->em->flush();
                return $user;
            })
        );
    }

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

    public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
    {
        return new RedirectResponse($this->urlGenerator->generate('app_login'));
    }
}