<?php
declare(strict_types=1);

namespace App\Tests\Game;

use App\Game\Entity\Game;
use App\Game\Entity\Player;
use App\Game\Entity\Session;
use App\Game\Entity\SessionSetting;
use App\Game\Enum\SessionSettingType;
use App\Game\Repository\SessionSettingRepository;
use App\Game\Service\GameResponseService;
use App\Game\Service\PlayerService;
use App\Tech\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use PHPUnit\Framework\TestCase;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\Mercure\HubInterface;
use Symfony\Component\Mercure\Update;

class GameResponseServiceChatVerifyCodeTest extends TestCase
{
    private $security;
    private $playerService;
    private $sessionSettingRepository;
    private $hub;
    private $entityManager;
    private $service;

    protected function setUp(): void
    {
        $this->security = $this->createMock(Security::class);
        $this->playerService = $this->createMock(PlayerService::class);
        $this->sessionSettingRepository = $this->createMock(SessionSettingRepository::class);
        $this->hub = $this->createMock(HubInterface::class);
        $this->entityManager = $this->createMock(EntityManagerInterface::class);

        $this->service = new GameResponseService(
            $this->security,
            $this->playerService,
            $this->sessionSettingRepository,
            $this->hub,
            $this->entityManager,
            'H:\escapepage'
        );

        $_ENV['MERCURE_TOPIC_BASE'] = 'http://test';
    }

    public function testChatRegeneratesVerifyCodesIfShared(): void
    {
        $user = new User();
        $user->setUsername('testuser');

        $game = $this->createMock(Game::class);
        $game->method('getNumberOfPlayers')->willReturn(4);

        $session = $this->createMock(Session::class);
        $session->method('getId')->willReturn(123);
        $session->method('getGame')->willReturn($game);

        $player = $this->createMock(Player::class);
        $player->method('getUser')->willReturn($user);
        $player->method('getScreen')->willReturn(1);
        $player->method('getSession')->willReturn($session);

        $this->security->method('getUser')->willReturn($user);
        $this->playerService->method('GetCurrentlyActiveAsPlayer')->willReturn($player);

        // Mock rights
        $rightsSetting = new SessionSetting();
        $rightsSetting->setValue(json_encode(['chat']));
        $this->sessionSettingRepository->method('getSetting')
            ->willReturnMap([
                [$session, SessionSettingType::RIGHTS_FOR_PLAYER1, $player, $rightsSetting],
            ]);

        // Mock verify codes
        $verifyCodesSetting = new SessionSetting();
        $initialCodes = ['2' => 'secret123', '3' => 'secret456'];
        $verifyCodesSetting->setValue(json_encode($initialCodes));

        // Setting repository map for multiple calls
        $this->sessionSettingRepository->method('getSetting')
            ->willReturnCallback(function($s, $t, $p = null) use ($rightsSetting, $verifyCodesSetting) {
                if ($t === SessionSettingType::RIGHTS_FOR_PLAYER1) return $rightsSetting;
                if ($t === SessionSettingType::VERIFY_CODES_FOR_PLAYER1) return $verifyCodesSetting;
                return null;
            });

        // Expect Mercure updates: 1 for chat, 1 for notification
        $this->hub->expects($this->exactly(2))
            ->method('publish');

        $this->entityManager->expects($this->once())
            ->method('flush');

        $raw = json_encode(['message' => '/chat Hello look at my code secret123', 'ts' => '123']);
        $result = $this->service->getGameResponse($raw);

        $this->assertEquals(['result' => ['succesfully send']], $result);

        $newCodes = json_decode($verifyCodesSetting->getValue(), true);
        $this->assertNotEquals('secret123', $newCodes['2']);
        $this->assertEquals('secret456', $newCodes['3']);
    }
}
