<?php

namespace App\Tests\Controller;

use App\Controller\SetPasswordController;
use App\Entity\User;
use App\Repository\UserRepository;
use Doctrine\ORM\EntityManagerInterface;
use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Routing\RouterInterface;
use Twig\Environment;

class SetPasswordControllerTest extends TestCase
{
    private function createController(Request $request): SetPasswordController
    {
        $twig = $this->createStub(Environment::class);
        $twig->method('render')->willReturn('<html></html>');
        $router = $this->createStub(RouterInterface::class);
        $router->method('generate')->willReturn('/');
        $requestStack = new RequestStack();
        $requestStack->push($request);

        $container = $this->createStub(ContainerInterface::class);
        $container->method('has')->willReturn(true);
        $container->method('get')->willReturnMap([
            ['twig', $twig],
            ['router', $router],
            ['request_stack', $requestStack],
        ]);

        $controller = new SetPasswordController();
        $controller->setContainer($container);

        return $controller;
    }

    public function testGetFormRendered(): void
    {
        $user = new User();
        $user->setEmail('t@t.com');
        $user->setFirstName('T');
        $user->setLastName('T');
        $user->setPassword('h');
        $user->setTempPassword('valid-token');

        $repo = $this->createStub(UserRepository::class);
        $repo->method('findOneBy')->willReturn($user);

        $request = new Request();
        $request->setSession(new Session(new MockArraySessionStorage()));
        $controller = $this->createController($request);

        $response = $controller->index('valid-token', $request, $repo, $this->createStub(UserPasswordHasherInterface::class), $this->createStub(EntityManagerInterface::class));
        $this->assertSame(200, $response->getStatusCode());
    }

    public function testTokenExpired(): void
    {
        $repo = $this->createStub(UserRepository::class);
        $repo->method('findOneBy')->willReturn(null);

        $request = new Request();
        $request->setSession(new Session(new MockArraySessionStorage()));
        $controller = $this->createController($request);

        $response = $controller->index('bad-token', $request, $repo, $this->createStub(UserPasswordHasherInterface::class), $this->createStub(EntityManagerInterface::class));
        $this->assertSame(200, $response->getStatusCode());
    }

    public function testPostPasswordTooShort(): void
    {
        $user = new User();
        $user->setEmail('t@t.com');
        $user->setFirstName('T');
        $user->setLastName('T');
        $user->setPassword('h');
        $user->setTempPassword('token');

        $repo = $this->createStub(UserRepository::class);
        $repo->method('findOneBy')->willReturn($user);

        $request = new Request([], ['password' => 'short', 'password_confirm' => 'short']);
        $request->setMethod('POST');
        $request->setSession(new Session(new MockArraySessionStorage()));
        $controller = $this->createController($request);

        $response = $controller->index('token', $request, $repo, $this->createStub(UserPasswordHasherInterface::class), $this->createStub(EntityManagerInterface::class));
        $this->assertSame(200, $response->getStatusCode());
    }

    public function testPostPasswordMismatch(): void
    {
        $user = new User();
        $user->setEmail('t@t.com');
        $user->setFirstName('T');
        $user->setLastName('T');
        $user->setPassword('h');
        $user->setTempPassword('token');

        $repo = $this->createStub(UserRepository::class);
        $repo->method('findOneBy')->willReturn($user);

        $request = new Request([], ['password' => 'password123', 'password_confirm' => 'different123']);
        $request->setMethod('POST');
        $request->setSession(new Session(new MockArraySessionStorage()));
        $controller = $this->createController($request);

        $response = $controller->index('token', $request, $repo, $this->createStub(UserPasswordHasherInterface::class), $this->createStub(EntityManagerInterface::class));
        $this->assertSame(200, $response->getStatusCode());
    }

    public function testPostSuccess(): void
    {
        $user = new User();
        $user->setEmail('t@t.com');
        $user->setFirstName('T');
        $user->setLastName('T');
        $user->setPassword('h');
        $user->setTempPassword('token');

        $repo = $this->createStub(UserRepository::class);
        $repo->method('findOneBy')->willReturn($user);

        $hasher = $this->createStub(UserPasswordHasherInterface::class);
        $hasher->method('hashPassword')->willReturn('hashed');

        $em = $this->createMock(EntityManagerInterface::class);
        $em->expects($this->once())->method('flush');

        $request = new Request([], ['password' => 'newpassword8', 'password_confirm' => 'newpassword8']);
        $request->setMethod('POST');
        $request->setSession(new Session(new MockArraySessionStorage()));
        $controller = $this->createController($request);

        $response = $controller->index('token', $request, $repo, $hasher, $em);
        $this->assertSame(302, $response->getStatusCode());
    }
}
