<?php

declare(strict_types=1);

namespace Tests\Framework\StaticSite;

use App\Framework\Core\Application;
use App\Framework\Http\Method;
use App\Framework\Http\HttpResponse;
use App\Framework\Http\Request;
use App\Framework\Http\Response;
use App\Framework\StaticSite\StaticSiteGenerator;
use PHPUnit\Framework\TestCase;

class StaticSiteGeneratorTest extends TestCase
{
    private $outputDir;
    private $app;

    protected function setUp(): void
    {
        parent::setUp();

        // Temporäres Verzeichnis für Tests erstellen
        $this->outputDir = sys_get_temp_dir() . '/static-site-test-' . uniqid();
        mkdir($this->outputDir, 0755, true);

        // Mock für Application erstellen
        $this->app = $this->createMock(Application::class);
    }

    protected function tearDown(): void
    {
        parent::tearDown();

        // Temporäres Verzeichnis nach dem Test löschen
        $this->removeDirectory($this->outputDir);
    }

    /**
     * Hilfsfunktion zum rekursiven Löschen eines Verzeichnisses
     */
    private function removeDirectory(string $dir): void
    {
        if (!is_dir($dir)) {
            return;
        }

        $files = array_diff(scandir($dir), ['.', '..']);

        foreach ($files as $file) {
            $path = $dir . '/' . $file;
            is_dir($path) ? $this->removeDirectory($path) : unlink($path);
        }

        rmdir($dir);
    }

    public function testGenerateCreatesStaticFiles(): void
    {
        // Testdaten vorbereiten
        $routes = ['/', '/about', '/blog/post-1'];
        $responseBody = '<html><body>Test Content</body></html>';

        // Mock für Response konfigurieren
        $response = $this->createMock(Response::class);
        $response->method('getBody')->willReturn($responseBody);

        // App-Mock konfigurieren, um Response zurückzugeben
        $this->app->method('handleRequest')->willReturn($response);

        // StaticSiteGenerator initialisieren
        $generator = new StaticSiteGenerator($this->app, $routes, $this->outputDir);

        // Statische Seiten generieren
        $generator->generate();

        // Prüfen, ob die erwarteten Dateien erstellt wurden
        $this->assertFileExists($this->outputDir . '/index.html');
        $this->assertFileExists($this->outputDir . '/about/index.html');
        $this->assertFileExists($this->outputDir . '/blog/post-1/index.html');

        // Prüfen, ob der Inhalt korrekt ist
        $this->assertEquals($responseBody, file_get_contents($this->outputDir . '/index.html'));
    }

    public function testGenerateHandlesExceptions(): void
    {
        // Testdaten vorbereiten
        $routes = ['/error-page'];

        // App-Mock konfigurieren, um eine Exception zu werfen
        $this->app->method('handleRequest')->willThrowException(new \Exception('Test Exception'));

        // StaticSiteGenerator initialisieren
        $generator = new StaticSiteGenerator($this->app, $routes, $this->outputDir);

        // Output-Buffer verwenden, um die Echo-Ausgaben zu erfassen
        ob_start();
        $generator->generate();
        $output = ob_get_clean();

        // Prüfen, ob die Fehlermeldung ausgegeben wurde
        $this->assertStringContainsString('Fehler beim Generieren von /error-page', $output);

        // Prüfen, ob keine Datei erstellt wurde
        $this->assertFileDoesNotExist($this->outputDir . '/error-page/index.html');
    }

    public function testGetFilePathForRoute(): void
    {
        // StaticSiteGenerator mit Reflection für private Methoden testen
        $generator = new StaticSiteGenerator($this->app, [], $this->outputDir);
        $reflection = new \ReflectionClass($generator);
        $method = $reflection->getMethod('getFilePathForRoute');
        $method->setAccessible(true);

        // Verschiedene Routentypen testen
        $this->assertEquals(
            $this->outputDir . '/index.html',
            $method->invoke($generator, '/')
        );

        $this->assertEquals(
            $this->outputDir . '/about/index.html',
            $method->invoke($generator, '/about')
        );

        $this->assertEquals(
            $this->outputDir . '/api/data.json',
            $method->invoke($generator, '/api/data.json')
        );
    }
}
