<?php

namespace App\EventSubscriber;

use App\Entity\User;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\AuthenticationEvents;
use Symfony\Component\Security\Core\Event\AuthenticationFailureEvent;
use Symfony\Component\Security\Core\Event\AuthenticationSuccessEvent;
use Symfony\Component\Security\Http\Event\DeauthenticatedEvent;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\Security\Http\Event\LoginFailureEvent;
use Symfony\Component\Security\Http\Event\LogoutEvent;
use Symfony\Component\Security\Http\Event\SwitchUserEvent;
use Symfony\Component\Security\Http\SecurityEvents;


class AuthenticationSubscriber implements EventSubscriberInterface
{
    /**
     * @var LoggerInterface
     */
    private $securityLogger;

    /**
     * @var RequestStack
     */
    private $request;

    /**
     * @param LoggerInterface $securityLogger
     * @param RequestStack $request
     */
    public function __construct(LoggerInterface $securityLogger, RequestStack $request)
    {
        $this->securityLogger = $securityLogger;
        $this->request = $request;
    }

    /**
     * @return array<string>
     */
    public static function getSubscribedEvents(): array
    {
        return [
            AuthenticationEvents::AUTHENTICATION_FAILURE        => 'onSecurityAuthenticationFailure',
            AuthenticationEvents::AUTHENTICATION_SUCCESS        => 'onSecurityAuthenticationSuccess',
            SecurityEvents::INTERACTIVE_LOGIN                   => 'onSecurityInteractiveLogin',
            'Symfony\Component\Security\Http\Event\LogoutEvent' => 'onSecurityLogout',
            'security.logout.on.change'                         => 'onSecurityLogoutOnChange',
            SecurityEvents::SWITCH_USER                         => 'onSecuritySwitchUser',

        ];
    }
    public function onSecurityAuthenticationFailure(AuthenticationFailureEvent $event): void
    {
        $securityToken=$event->getAuthenticationToken();
        $userEmail=$this->getUserEmail($securityToken);
        ["user_IP" => $userIP]= $this->getRouteNameAndUserIP();
        $this->securityLogger->info("the user with email '{$userEmail} and IP address '{$userIP}' has tried to connect unsuccessfully.");


    }

    public function onSecurityAuthenticationSuccess(AuthenticationSuccessEvent $event): void
    {

        [
            "user_IP"       => $userIP,
            "user_route"    => $userRoute

        ]= $this->getRouteNameAndUserIP();

        // https://github.com/php-fig/log
        if (empty($event->getAuthenticationToken()->getRoleNames())) {
            $this->securityLogger->info("An anonymous user having the IP address '{$userIP}'
                ' is using this route '{$userRoute}'");
        }
        else
        {
            $securityToken=$event->getAuthenticationToken();

            $userEmail=$this->getUserEmail($securityToken);

            $this->securityLogger->info("the user with email '{$userEmail} and IP address '{$userIP}' has been connected.");
        }


    }
    public function onSecurityInteractiveLogin(InteractiveLoginEvent $event): void
    {
        ["user_IP" => $userIP]= $this->getRouteNameAndUserIP();
        $authenticationToken = $event->getAuthenticationToken();
        $userEmail= $this->getUserEmail($authenticationToken);
        $this->securityLogger->info("An user having the IP address '{$userIP}'
                ' is connected using '{$userEmail}'");
    }

    public function onSecurityLogout(LogoutEvent $event): void
    {
        $response=$event->getResponse();
        $securityToken=$event->getToken();

        if (!$response || ! $securityToken)
            return;

        ["user_IP" => $userIP]= $this->getRouteNameAndUserIP();
        $userEmail= $this->getUserEmail($securityToken);
        $this->securityLogger->info("An user having the IP address '{$userIP}'
                ' is disconnected using '{$userEmail}'");

    }

    public function onSecurityLogoutOnChange(DeauthenticatedEvent $event): void
    {


    }

    public function onSecuritySwitchUser(SwitchUserEvent $event): void
    {


    }

    /**
     * Return the IP adress of the user and the name of the route the user has reached.
     * @return array{user_IP: string|null, user_route: mixed}
     */
    private function getRouteNameAndUserIP(): array{
        $request=$this->request->getCurrentRequest();
        if (!$request)
            return [
                "user_IP"       => "unknown",
                "user_route"    => "unknown"
            ];
        return [
            "user_IP"       => $request->getClientIp()?? 'Unknown',
            "user_route"    => $request->attributes->get('_route')
        ];
    }

    /**
     * @param TokenInterface $securityToken
     * @return string
     */
    private function getUserEmail(TokenInterface $securityToken) :? string
    {
        /** @var User $user */
        $user= $securityToken->getUser();
        return $user->getEmail();
    }
}
