<?php

namespace Tests\Feature;

use App\Helpers\StringHelper;
use App\Models\Post;
use App\Models\PostTranslation;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class PostContentXssProtectionTest extends TestCase
{
    use RefreshDatabase;

    /**
     * Test that the sanitizeHtml method properly escapes script tags.
     *
     * @return void
     */
    public function test_post_content_escapes_script_tags()
    {
        $maliciousContent = '<p>Hello</p><script>alert("XSS")</script><p>World</p>';

        $sanitized = StringHelper::sanitizeHtml($maliciousContent);

        // Script tags should be completely removed
        $this->assertStringNotContainsString('<script>', $sanitized);
        $this->assertStringNotContainsString('alert("XSS")', $sanitized);

        // Safe HTML should be preserved
        $this->assertStringContainsString('<p>Hello</p>', $sanitized);
        $this->assertStringContainsString('<p>World</p>', $sanitized);
    }

    /**
     * Test that img tag with onerror handler is sanitized.
     *
     * @return void
     */
    public function test_post_content_sanitizes_img_onerror()
    {
        $maliciousContent = '<p>Check this image</p><img src="x" onerror="alert(document.cookie)" />';

        $sanitized = StringHelper::sanitizeHtml($maliciousContent);

        // Image should be allowed but without dangerous attributes
        $this->assertStringContainsString('<img', $sanitized);
        $this->assertStringNotContainsString('onerror', $sanitized);
        $this->assertStringNotContainsString('alert(document.cookie)', $sanitized);
    }

    /**
     * Test that iframe injection is completely removed.
     *
     * @return void
     */
    public function test_post_content_removes_iframe()
    {
        $maliciousContent = '<p>Content</p><iframe src="https://evil.com"></iframe><p>More content</p>';

        $sanitized = StringHelper::sanitizeHtml($maliciousContent);

        // Iframe should be completely removed
        $this->assertStringNotContainsString('<iframe', $sanitized);
        $this->assertStringNotContainsString('evil.com', $sanitized);

        // Safe content preserved
        $this->assertStringContainsString('<p>Content</p>', $sanitized);
        $this->assertStringContainsString('<p>More content</p>', $sanitized);
    }

    /**
     * Test that safe rich text formatting is preserved.
     *
     * @return void
     */
    public function test_post_content_preserves_safe_formatting()
    {
        $safeContent = '<h1>Title</h1><p>Paragraph with <strong>bold</strong> and <em>italic</em> text.</p><ul><li>Item 1</li><li>Item 2</li></ul><a href="https://example.com">Link</a>';

        $sanitized = StringHelper::sanitizeHtml($safeContent);

        // All safe formatting should be preserved
        $this->assertStringContainsString('<h1>Title</h1>', $sanitized);
        $this->assertStringContainsString('<strong>bold</strong>', $sanitized);
        $this->assertStringContainsString('<em>italic</em>', $sanitized);
        $this->assertStringContainsString('<ul>', $sanitized);
        $this->assertStringContainsString('<li>Item 1</li>', $sanitized);
        $this->assertStringContainsString('<a href="https://example.com">Link</a>', $sanitized);
    }

    /**
     * Test that event handler attributes are removed.
     *
     * @return void
     */
    public function test_post_content_removes_event_handlers()
    {
        $maliciousContent = '<a href="#" onclick="alert(1)">Click me</a><div onmouseover="steal()">Hover</div>';

        $sanitized = StringHelper::sanitizeHtml($maliciousContent);

        // Event handlers should be removed
        $this->assertStringNotContainsString('onclick', $sanitized);
        $this->assertStringNotContainsString('onmouseover', $sanitized);
        $this->assertStringNotContainsString('alert(1)', $sanitized);
        $this->assertStringNotContainsString('steal()', $sanitized);

        // Safe parts should remain (div is allowed with class attribute)
        $this->assertStringContainsString('Click me', $sanitized);
        $this->assertStringContainsString('Hover', $sanitized);
    }

    /**
     * Test that data URIs with JavaScript are removed.
     *
     * @return void
     */
    public function test_post_content_removes_javascript_data_uris()
    {
        $maliciousContent = '<a href="data:text/html,<script>alert(1)</script>">Click</a>';

        $sanitized = StringHelper::sanitizeHtml($maliciousContent);

        // JavaScript data URIs should be removed
        $this->assertStringNotContainsString('data:text/html', $sanitized);
        $this->assertStringNotContainsString('<script>', $sanitized);
    }

    /**
     * Test that style tags with CSS injection are removed.
     *
     * @return void
     */
    public function test_post_content_removes_style_tags()
    {
        $maliciousContent = '<p>Text</p><style>body { background: url("javascript:alert(1)") }</style>';

        $sanitized = StringHelper::sanitizeHtml($maliciousContent);

        // Style tags should be removed
        $this->assertStringNotContainsString('<style>', $sanitized);
        $this->assertStringNotContainsString('javascript:alert', $sanitized);
    }

    /**
     * Test that object and embed tags are removed.
     *
     * @return void
     */
    public function test_post_content_removes_object_embed_tags()
    {
        $maliciousContent = '<object data="malicious.swf"></object><embed src="evil.swf">';

        $sanitized = StringHelper::sanitizeHtml($maliciousContent);

        // Object and embed tags should be removed
        $this->assertStringNotContainsString('<object', $sanitized);
        $this->assertStringNotContainsString('<embed', $sanitized);
        $this->assertStringNotContainsString('malicious.swf', $sanitized);
    }

    /**
     * Test that null input returns empty string.
     *
     * @return void
     */
    public function test_post_content_handles_null_input()
    {
        $sanitized = StringHelper::sanitizeHtml(null);

        $this->assertEquals('', $sanitized);
    }

    /**
     * Test that empty string returns empty string.
     *
     * @return void
     */
    public function test_post_content_handles_empty_string()
    {
        $sanitized = StringHelper::sanitizeHtml('');

        $this->assertEquals('', $sanitized);
    }

    /**
     * Test that table HTML is preserved for structured content.
     *
     * @return void
     */
    public function test_post_content_preserves_tables()
    {
        $tableContent = '<table><thead><tr><th>Header</th></tr></thead><tbody><tr><td>Data</td></tr></tbody></table>';

        $sanitized = StringHelper::sanitizeHtml($tableContent);

        // Table structure should be preserved
        $this->assertStringContainsString('<table>', $sanitized);
        $this->assertStringContainsString('<thead>', $sanitized);
        $this->assertStringContainsString('<th>Header</th>', $sanitized);
        $this->assertStringContainsString('<tbody>', $sanitized);
        $this->assertStringContainsString('<td>Data</td>', $sanitized);
    }

    /**
     * Test that images with valid attributes are preserved.
     *
     * @return void
     */
    public function test_post_content_preserves_safe_images()
    {
        $imageContent = '<img src="https://example.com/image.jpg" alt="Description" width="500" height="300" title="My Image">';

        $sanitized = StringHelper::sanitizeHtml($imageContent);

        // Valid image attributes should be preserved
        $this->assertStringContainsString('src="https://example.com/image.jpg"', $sanitized);
        $this->assertStringContainsString('alt="Description"', $sanitized);
        $this->assertStringContainsString('width="500"', $sanitized);
        $this->assertStringContainsString('height="300"', $sanitized);
        $this->assertStringContainsString('title="My Image"', $sanitized);
    }

    /**
     * Test that links with target="_blank" are preserved.
     *
     * @return void
     */
    public function test_post_content_preserves_target_blank_links()
    {
        $linkContent = '<a href="https://example.com" target="_blank" title="External Link">Visit</a>';

        $sanitized = StringHelper::sanitizeHtml($linkContent);

        // Link with target="_blank" should be preserved
        $this->assertStringContainsString('href="https://example.com"', $sanitized);
        $this->assertStringContainsString('target="_blank"', $sanitized);
        $this->assertStringContainsString('title="External Link"', $sanitized);
    }

    /**
     * Test mixed safe and unsafe content.
     *
     * @return void
     */
    public function test_post_content_handles_mixed_content()
    {
        $mixedContent = '<h2>Article Title</h2><p>This is <strong>safe</strong> content.</p><script>alert("unsafe")</script><p>More safe content with <a href="https://example.com">a link</a>.</p>';

        $sanitized = StringHelper::sanitizeHtml($mixedContent);

        // Safe content preserved
        $this->assertStringContainsString('<h2>Article Title</h2>', $sanitized);
        $this->assertStringContainsString('<strong>safe</strong>', $sanitized);
        $this->assertStringContainsString('<a href="https://example.com">a link</a>', $sanitized);

        // Unsafe content removed
        $this->assertStringNotContainsString('<script>', $sanitized);
        $this->assertStringNotContainsString('alert("unsafe")', $sanitized);
    }

    /**
     * Test that code and pre tags are preserved for technical content.
     *
     * @return void
     */
    public function test_post_content_preserves_code_blocks()
    {
        $codeContent = '<pre><code>function hello() { return "world"; }</code></pre>';

        $sanitized = StringHelper::sanitizeHtml($codeContent);

        // Code blocks should be preserved
        $this->assertStringContainsString('<pre>', $sanitized);
        $this->assertStringContainsString('<code>', $sanitized);
        $this->assertStringContainsString('function hello()', $sanitized);
    }

    /**
     * Test SVG injection attempts are blocked.
     *
     * @return void
     */
    public function test_post_content_blocks_svg_injection()
    {
        $maliciousContent = '<svg onload="alert(1)"><circle cx="50" cy="50" r="40"/></svg>';

        $sanitized = StringHelper::sanitizeHtml($maliciousContent);

        // SVG should be removed (not in allowed tags list)
        $this->assertStringNotContainsString('<svg', $sanitized);
        $this->assertStringNotContainsString('onload', $sanitized);
        $this->assertStringNotContainsString('alert(1)', $sanitized);
    }
}
