<?php

declare(strict_types=1);

namespace App\Tests\Unit\Scolarite\Infrastructure\Service;

use App\Scolarite\Infrastructure\Service\HomeworkHtmlSanitizer;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HtmlSanitizer\HtmlSanitizer;
use Symfony\Component\HtmlSanitizer\HtmlSanitizerConfig;

final class HomeworkHtmlSanitizerTest extends TestCase
{
    private HomeworkHtmlSanitizer $sanitizer;

    protected function setUp(): void
    {
        $config = (new HtmlSanitizerConfig())
            ->allowElement('p')
            ->allowElement('br')
            ->allowElement('strong')
            ->allowElement('em')
            ->allowElement('ul')
            ->allowElement('ol')
            ->allowElement('li')
            ->allowElement('a', ['href', 'target', 'rel']);

        $this->sanitizer = new HomeworkHtmlSanitizer(new HtmlSanitizer($config));
    }

    #[Test]
    public function itAllowsBoldText(): void
    {
        $html = '<p>Texte <strong>en gras</strong></p>';

        self::assertSame($html, $this->sanitizer->sanitize($html));
    }

    #[Test]
    public function itAllowsItalicText(): void
    {
        $html = '<p>Texte <em>en italique</em></p>';

        self::assertSame($html, $this->sanitizer->sanitize($html));
    }

    #[Test]
    public function itAllowsUnorderedLists(): void
    {
        $html = '<ul><li>Élément 1</li><li>Élément 2</li></ul>';

        self::assertSame($html, $this->sanitizer->sanitize($html));
    }

    #[Test]
    public function itAllowsOrderedLists(): void
    {
        $html = '<ol><li>Premier</li><li>Deuxième</li></ol>';

        self::assertSame($html, $this->sanitizer->sanitize($html));
    }

    #[Test]
    public function itAllowsLinksWithSafeAttributes(): void
    {
        $html = '<p><a href="https://example.com" target="_blank" rel="noopener noreferrer">Lien</a></p>';

        self::assertSame($html, $this->sanitizer->sanitize($html));
    }

    #[Test]
    public function itStripsScriptTags(): void
    {
        $result = $this->sanitizer->sanitize('<p>Texte</p><script>alert("xss")</script>');

        self::assertStringNotContainsString('<script>', $result);
        self::assertStringNotContainsString('alert', $result);
    }

    #[Test]
    public function itStripsEventHandlers(): void
    {
        $result = $this->sanitizer->sanitize('<p onclick="alert(1)">Texte</p>');

        self::assertStringNotContainsString('onclick', $result);
        self::assertStringContainsString('Texte', $result);
    }

    #[Test]
    public function itStripsStyleTags(): void
    {
        $result = $this->sanitizer->sanitize('<style>body{display:none}</style><p>Texte</p>');

        self::assertStringNotContainsString('<style>', $result);
        self::assertStringContainsString('Texte', $result);
    }

    #[Test]
    public function itStripsIframeTags(): void
    {
        $result = $this->sanitizer->sanitize('<p>Texte</p><iframe src="evil.com"></iframe>');

        self::assertStringNotContainsString('<iframe>', $result);
    }

    #[Test]
    public function itStripsImgTags(): void
    {
        $result = $this->sanitizer->sanitize('<p>Texte</p><img src="x" onerror="alert(1)">');

        self::assertStringNotContainsString('<img', $result);
        self::assertStringNotContainsString('onerror', $result);
    }

    #[Test]
    public function itHandlesEmptyString(): void
    {
        self::assertSame('', $this->sanitizer->sanitize(''));
    }

    #[Test]
    public function itHandlesPlainText(): void
    {
        $result = $this->sanitizer->sanitize('Texte simple sans HTML');

        self::assertSame('Texte simple sans HTML', $result);
    }

    #[Test]
    public function itStripsJavascriptLinks(): void
    {
        $result = $this->sanitizer->sanitize('<a href="javascript:alert(1)">Clic</a>');

        self::assertStringNotContainsString('javascript:', $result);
    }

    #[Test]
    #[DataProvider('richContentProvider')]
    public function itPreservesRichContent(string $input, string $expectedSubstring): void
    {
        $result = $this->sanitizer->sanitize($input);

        self::assertStringContainsString($expectedSubstring, $result);
    }

    /** @return iterable<string, array{string, string}> */
    public static function richContentProvider(): iterable
    {
        yield 'gras' => ['<strong>gras</strong>', '<strong>gras</strong>'];
        yield 'italique' => ['<em>italique</em>', '<em>italique</em>'];
        yield 'liste à puces' => ['<ul><li>item</li></ul>', '<li>item</li>'];
        yield 'liste numérotée' => ['<ol><li>item</li></ol>', '<ol>'];
        yield 'paragraphe' => ['<p>texte</p>', '<p>texte</p>'];
        yield 'lien' => ['<a href="https://x.com">lien</a>', 'href="https://x.com"'];
    }
}
