<?php

namespace App\Tests\Command;

use App\Command\GitSyncLogCommand;
use App\Service\AI\GeminiClient;
use App\Service\System\GitClient;
use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Tester\CommandTester;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use Symfony\Contracts\HttpClient\ResponseInterface;

#[AllowMockObjectsWithoutExpectations]
class GitSyncLogCommandTest extends TestCase
{
    private MockObject&HttpClientInterface $httpClient;
    private MockObject&KernelInterface $kernel;
    private MockObject&GitClient $gitClient;
    private MockObject&GeminiClient $geminiClient;
    private string $tempDir;

    protected function setUp(): void
    {
        $this->httpClient = $this->createMock(HttpClientInterface::class);
        $this->kernel = $this->createMock(KernelInterface::class);
        $this->gitClient = $this->createMock(GitClient::class);
        $this->geminiClient = $this->createMock(GeminiClient::class);

        $this->tempDir = sys_get_temp_dir() . '/git_log_test_' . uniqid();
        mkdir($this->tempDir . '/var', 0777, true);
    }

    protected function tearDown(): void
    {
        $this->removeDirectory($this->tempDir);
    }

    public function testExecuteNewCommit()
    {
        // 1. Setup Mocks
        $this->kernel->method('getProjectDir')->willReturn($this->tempDir);

        $this->gitClient->expects($this->once())
            ->method('getLastCommitInfo')
            ->willReturn([
                'message' => 'feat: add awesome feature',
                'date' => '2026-01-30 10:00:00',
                'hash' => 'hash123'
            ]);

        $this->geminiClient->expects($this->once())
            ->method('generateFriendlyMessage')
            ->with('feat: add awesome feature')
            ->willReturn('Super nouvelle fonctionnalité ajoutée !');

        $this->httpClient->expects($this->once())
            ->method('request')
            ->with('POST', $this->stringContains('discord.com'), $this->arrayHasKey('json'));

        // 2. Execute
        $command = new GitSyncLogCommand(
            $this->httpClient,
            $this->kernel,
            $this->gitClient,
            $this->geminiClient
        );
        $application = new Application();
        $application->addCommand($command);
        $commandTester = new CommandTester($application->find('app:git-log-update'));

        $commandTester->execute([]);

        // 3. Assert Output
        $output = $commandTester->getDisplay();
        $this->assertStringContainsString('Journal client mis à jour avec succès', $output);

        // 4. Assert File Content
        $filePath = $this->tempDir . '/var/update.json';
        $this->assertFileExists($filePath);
        $data = json_decode(file_get_contents($filePath), true);
        $this->assertCount(1, $data);
        $this->assertEquals('feature', $data[0]['type']);
        $this->assertEquals('Super nouvelle fonctionnalité ajoutée !', $data[0]['message']);
        $this->assertEquals('hash123', $data[0]['hash']);
    }

    public function testExecuteAlreadyUpToDate()
    {
        // 1. Setup File
        $filePath = $this->tempDir . '/var/update.json';
        file_put_contents($filePath, json_encode([
            ['hash' => 'hash123']
        ]));

        // 2. Setup Mocks
        $this->kernel->method('getProjectDir')->willReturn($this->tempDir);

        $this->gitClient->expects($this->once())
            ->method('getLastCommitInfo')
            ->willReturn([
                'message' => 'fix: bug',
                'date' => '2026-01-30 12:00:00',
                'hash' => 'hash123' // Same hash
            ]);

        // Gemini & Discord should NOT be called
        $this->geminiClient->expects($this->never())->method('generateFriendlyMessage');
        $this->httpClient->expects($this->never())->method('request');

        // 3. Execute
        $command = new GitSyncLogCommand(
            $this->httpClient,
            $this->kernel,
            $this->gitClient,
            $this->geminiClient
        );
        $application = new Application();
        $application->addCommand($command);
        $commandTester = new CommandTester($application->find('app:git-log-update'));

        $commandTester->execute([]);

        // 4. Assert Output
        $output = $commandTester->getDisplay();
        $this->assertStringContainsString('déjà à jour', $output);
    }

    private function removeDirectory($dir) {
        if (!is_dir($dir)) return;
        $files = array_diff(scandir($dir), array('.','..'));
        foreach ($files as $file) {
            (is_dir("$dir/$file")) ? $this->removeDirectory("$dir/$file") : unlink("$dir/$file");
        }
        rmdir($dir);
    }
}
