<?php

namespace App\Security;

use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use KnpU\OAuth2ClientBundle\Client\ClientRegistry;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\Authenticator\AbstractLoginFormAuthenticator;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\CsrfTokenBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\RememberMeBadge;
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\Security\Http\Util\TargetPathTrait;

class KeycloakAuthenticator extends AbstractLoginFormAuthenticator implements AuthenticationEntryPointInterface
{
    use TargetPathTrait;

    private ClientRegistry $clientRegistry;
    private UrlGeneratorInterface $urlGenerator;
    private EntityManagerInterface $entityManager;
    public function __construct(ClientRegistry $clientRegistry, UrlGeneratorInterface $urlGenerator, EntityManagerInterface $entityManager)
    {
        $this->clientRegistry = $clientRegistry;
        $this->urlGenerator = $urlGenerator;
        $this->entityManager = $entityManager;
    }
    public function supports(Request $request): bool
    {
        return $request->getPathInfo() === '/oauth/check/keycloak' && $request->isMethod('GET');
    }
    public function authenticate(Request $request): SelfValidatingPassport
    {
        /** @var \KnpU\OAuth2ClientBundle\Client\OAuth2ClientInterface $client */
        $client = $this->clientRegistry->getClient('keycloak');
        $keycloakUser = $client->fetchUser();
        $data = $keycloakUser->toArray();

        $keycloakId = $keycloakUser->getId();
        $email      = $keycloakUser->getEmail();
        $firstName  = $keycloakUser->getFirstName();
        $lastName   = $keycloakUser->getLastName();

        $rolesKeycloak = $data['realm_access']['roles'] ?? [];

        $user = $this->entityManager
            ->getRepository(User::class)
            ->findOneBy(['keycloakId' => $keycloakId]);

        if (!$user) {
            $user = new User();
            $user->setKeycloakId($keycloakId);
            $this->entityManager->persist($user);
        }

        $user->setEmail($email);
        $user->setFirstName($firstName);
        $user->setLastName($lastName);

        $roles = [];

        if (in_array('ROLE_ADMIN', $rolesKeycloak, true)) {
            $roles[] = 'ROLE_ADMIN';
        }

        if (in_array('ROLE_USER', $rolesKeycloak, true)) {
            $roles[] = 'ROLE_USER';
        }

        if (in_array('ROLE_DEVELOPER', $rolesKeycloak, true)) {
            $roles[] = 'ROLE_DEVELOPER';
        }

        if (empty($roles)) {
            $roles[] = 'ROLE_USER';
        }

        $user->setRoles($roles);

        $this->entityManager->flush();

        return new SelfValidatingPassport(
            new UserBadge($user->getId(), fn() => $user)
        );
    }
    public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
    {
        $roles = $token->getUser()->getRoles();
        if (in_array('ROLE_ADMIN', $roles, true) || in_array('ROLE_DEVELOPER', $roles, true)) {
            return new RedirectResponse($this->urlGenerator->generate('admin_dashboard'));
        }
        $targetPath = $this->getTargetPath($request->getSession(), $firewallName);
        return new RedirectResponse($targetPath ?: $this->urlGenerator->generate('home'));
    }
    public function onAuthenticationFailure(Request $request, AuthenticationException $exception): Response
    {
        $errorMessage = strtr($exception->getMessageKey() ?: 'Authentication failed.', $exception->getMessageData());
        return new Response($errorMessage, Response::HTTP_FORBIDDEN);
    }
    public function start(Request $request, ?AuthenticationException $authException = null): Response
    {
        return new RedirectResponse(
            $this->urlGenerator->generate('connect_keycloak_start')
        );
    }
    protected function getLoginUrl(Request $request): string
    {
        return $this->urlGenerator->generate('connect_keycloak_start');
    }
}
