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

use App\Entity\Account;
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\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;
use Symfony\Component\Uid\Uuid;

class EtlKeycloakAuthenticator extends OAuth2Authenticator implements AuthenticationEntryPointInterface
{
    private $clientRegistry;
    private $entityManager;
    private $router;

    public function __construct(ClientRegistry $clientRegistry, EntityManagerInterface $entityManager, RouterInterface $router)
    {
        $this->clientRegistry = $clientRegistry;
        $this->entityManager = $entityManager;
        $this->router = $router;
    }

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

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

        return new SelfValidatingPassport(
            new UserBadge($accessToken->getToken(), function() use ($accessToken, $client) {
                /** @var \Stevenmaguire\OAuth2\Client\Provider\KeycloakResourceOwner $keycloakUser */
                $keycloakUser = $client->fetchUserFromToken($accessToken);

                $email = $keycloakUser->getEmail();

                $existingUser = $this->entityManager->getRepository(Account::class)->findOneBy(['keycloakId' => $keycloakUser->getId()]);

                if ($existingUser) {
                    return $existingUser;
                }

                // Sync by email
                $user = $this->entityManager->getRepository(Account::class)->findOneBy(['email' => $email]);

                if (!$user) {
                    // Create new Account (Admin) if not exists
                    $user = new Account();
                    $user->setUuid(Uuid::v4());
                    $user->setRoles(['ROLE_ADMIN']); // Default to ADMIN for SSO users here? Or keep ROOT like original? Original had ROOT.
                    // Let's stick to original logic but maybe be safer with ROLE_ADMIN if unsure. The original used ROLE_ROOT.
                    // I'll keep ROLE_ROOT to match behavior, though risky.
                    $user->setRoles(['ROLE_ROOT']);
                    $user->setIsActif(true);
                    $user->setIsFirstLogin(false);
                    $user->setUsername($keycloakUser->getUsername());
                    $user->setFirstName($keycloakUser->toArray()['given_name']);
                    $user->setName($keycloakUser->toArray()['family_name']);
                    $user->setEmail($email);
                }

                $user->setKeycloakId($keycloakUser->getId());
                $this->entityManager->persist($user);
                $this->entityManager->flush();

                return $user;
            })
        );
    }

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

    public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
    {
        $message = strtr($exception->getMessageKey(), $exception->getMessageData());
        return new Response($message, Response::HTTP_FORBIDDEN);
    }

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