<?php

declare(strict_types=1);

namespace NoahVet\Reef\Phpunit;

use HWI\Bundle\OAuthBundle\Security\Core\Authentication\Token\OAuthToken;
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
use Symfony\Component\BrowserKit\Cookie;
use Symfony\Component\HttpFoundation\Session\SessionFactoryInterface;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\User\UserInterface;

class HWIOauthKernelBrowser extends KernelBrowser
{
    public function __construct(
        KernelBrowser $browser,
    ) {
        parent::__construct(
            $browser->getKernel(),
            $browser->server,
            $browser->history,
            $browser->cookieJar,
        );
    }

    public function loginUserOauth(
        object $user,
        string $firewallContext = 'main',
        string $bearer = 'hwi_access_token',
    ): self {
        if (!\interface_exists(UserInterface::class)) {
            throw new \LogicException(\sprintf('"%s" requires symfony/security-core to be installed.', __METHOD__));
        }

        if (!$user instanceof UserInterface) {
            throw new \LogicException(
                \sprintf(
                    'The first argument of "%s" must be instance of "%s", "%s" provided.',
                    __METHOD__,
                    UserInterface::class,
                    $user::class,
                ),
            );
        }

        $token = new OAuthToken($bearer, $user->getRoles());
        $token->setResourceOwnerName('noahvet');
        $token->setUser($user);
        $token->setExpiresIn(3600);
        /*
         * @deprecated since Symfony 5.4
         * @phpstan-ignore-next-line
         */
        if (\method_exists($token, 'setAuthenticated')) {
            $token->setAuthenticated(true, false);
        }

        $container = $this->getContainer();
        /** @var TokenStorageInterface $tokenStorage */
        $tokenStorage = $container->get('security.untracked_token_storage');
        $tokenStorage->setToken($token);

        if ($container->has('session.factory')) {
            /** @var SessionFactoryInterface $sessionFactory */
            $sessionFactory = $container->get('session.factory');
            $session = $sessionFactory->createSession();
        } elseif ($container->has('session')) {
            /** @var SessionInterface $session */
            $session = $container->get('session');
        } else {
            return $this;
        }

        $session->set('_security_'.$firewallContext, \serialize($token));
        $session->save();

        $domains = \array_unique(
            \array_map(
                fn (Cookie $cookie) => $cookie->getName() === $session->getName() ? $cookie->getDomain() : '',
                $this->getCookieJar()->all(),
            ),
        ) ?: [''];
        foreach ($domains as $domain) {
            $cookie = new Cookie($session->getName(), $session->getId(), null, null, $domain);
            $this->getCookieJar()->set($cookie);
        }

        return $this;
    }
}
