<?php

namespace Tests\Feature;

use App\Http\Livewire\MainSearchBar;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Livewire;
use Tests\TestCase;

class SearchXssProtectionTest extends TestCase
{
    use RefreshDatabase;

    /**
     * Test that the sanitizeHighlights method properly escapes XSS attempts.
     *
     * @return void
     */
    public function test_search_highlights_escape_script_tags()
    {
        // Create a test user
        $user = User::factory()->create([
            'name' => 'Test User',
            'email' => 'test@example.com',
        ]);

        // Authenticate as the user
        $this->actingAs($user);

        // Create MainSearchBar component instance
        $component = new MainSearchBar();

        // Use reflection to access the private sanitizeHighlights method
        $reflection = new \ReflectionClass($component);
        $method = $reflection->getMethod('sanitizeHighlights');
        $method->setAccessible(true);

        // Test 1: Simple script tag injection
        $maliciousHighlights = [
            'about_short_en' => [
                'I am a developer <script>alert("XSS")</script> looking for work'
            ]
        ];

        $sanitized = $method->invoke($component, $maliciousHighlights);

        $this->assertStringNotContainsString('<script>', $sanitized['about_short_en'][0]);
        $this->assertStringContainsString('&lt;script&gt;', $sanitized['about_short_en'][0]);
    }

    /**
     * Test that img tag with onerror handler is escaped.
     *
     * @return void
     */
    public function test_search_highlights_escape_img_onerror()
    {
        $user = User::factory()->create();
        $this->actingAs($user);

        $component = new MainSearchBar();
        $reflection = new \ReflectionClass($component);
        $method = $reflection->getMethod('sanitizeHighlights');
        $method->setAccessible(true);

        $maliciousHighlights = [
            'about_en' => [
                'Contact me <img src=x onerror=alert(document.cookie)> for projects'
            ]
        ];

        $sanitized = $method->invoke($component, $maliciousHighlights);

        // The img tag should be escaped
        $this->assertStringNotContainsString('<img', $sanitized['about_en'][0]);
        $this->assertStringContainsString('&lt;img', $sanitized['about_en'][0]);
        // The equals sign in the attribute should be escaped, making it safe
        $this->assertStringContainsString('src=x', $sanitized['about_en'][0]); // Text 'onerror' may remain but is harmless when HTML is escaped
    }

    /**
     * Test that iframe injection is escaped.
     *
     * @return void
     */
    public function test_search_highlights_escape_iframe()
    {
        $user = User::factory()->create();
        $this->actingAs($user);

        $component = new MainSearchBar();
        $reflection = new \ReflectionClass($component);
        $method = $reflection->getMethod('sanitizeHighlights');
        $method->setAccessible(true);

        $maliciousHighlights = [
            'motivation_en' => [
                'My motivation <iframe src="https://evil.com"></iframe> is strong'
            ]
        ];

        $sanitized = $method->invoke($component, $maliciousHighlights);

        $this->assertStringNotContainsString('<iframe', $sanitized['motivation_en'][0]);
        $this->assertStringContainsString('&lt;iframe', $sanitized['motivation_en'][0]);
    }

    /**
     * Test that Elasticsearch highlight tags are preserved.
     *
     * @return void
     */
    public function test_search_highlights_preserve_elasticsearch_tags()
    {
        $user = User::factory()->create();
        $this->actingAs($user);

        $component = new MainSearchBar();
        $reflection = new \ReflectionClass($component);
        $method = $reflection->getMethod('sanitizeHighlights');
        $method->setAccessible(true);

        // Simulate Elasticsearch highlight with configured tags
        $validHighlights = [
            'name' => [
                'John <span class="font-semibold text-white leading-tight">Smith</span>'
            ]
        ];

        $sanitized = $method->invoke($component, $validHighlights);

        // Elasticsearch highlight tags should be preserved
        $this->assertStringContainsString('<span class="font-semibold text-white leading-tight">Smith</span>', $sanitized['name'][0]);
        $this->assertStringContainsString('John', $sanitized['name'][0]);
    }

    /**
     * Test that user content with special characters is escaped but highlight tags preserved.
     *
     * @return void
     */
    public function test_search_highlights_escape_user_content_preserve_highlight_tags()
    {
        $user = User::factory()->create();
        $this->actingAs($user);

        $component = new MainSearchBar();
        $reflection = new \ReflectionClass($component);
        $method = $reflection->getMethod('sanitizeHighlights');
        $method->setAccessible(true);

        // User content with XSS attempt + Elasticsearch highlight tags
        $mixedHighlights = [
            'about_short_en' => [
                'I love <span class="font-semibold text-white leading-tight">coding</span> <script>alert("XSS")</script>'
            ]
        ];

        $sanitized = $method->invoke($component, $mixedHighlights);

        // Elasticsearch tags preserved
        $this->assertStringContainsString('<span class="font-semibold text-white leading-tight">coding</span>', $sanitized['about_short_en'][0]);

        // User XSS attempt escaped
        $this->assertStringNotContainsString('<script>alert("XSS")</script>', $sanitized['about_short_en'][0]);
        $this->assertStringContainsString('&lt;script&gt;', $sanitized['about_short_en'][0]);
    }

    /**
     * Test that empty highlights array is handled correctly.
     *
     * @return void
     */
    public function test_search_highlights_handle_empty_array()
    {
        $user = User::factory()->create();
        $this->actingAs($user);

        $component = new MainSearchBar();
        $reflection = new \ReflectionClass($component);
        $method = $reflection->getMethod('sanitizeHighlights');
        $method->setAccessible(true);

        $emptyHighlights = [];
        $sanitized = $method->invoke($component, $emptyHighlights);

        $this->assertEmpty($sanitized);
    }

    /**
     * Test that event handler attributes are escaped.
     *
     * @return void
     */
    public function test_search_highlights_escape_event_handlers()
    {
        $user = User::factory()->create();
        $this->actingAs($user);

        $component = new MainSearchBar();
        $reflection = new \ReflectionClass($component);
        $method = $reflection->getMethod('sanitizeHighlights');
        $method->setAccessible(true);

        $maliciousHighlights = [
            'about_en' => [
                'Click <a href="#" onclick="alert(1)">here</a> for more info'
            ]
        ];

        $sanitized = $method->invoke($component, $maliciousHighlights);

        // The anchor tag and attributes should be escaped
        $this->assertStringNotContainsString('<a href', $sanitized['about_en'][0]);
        $this->assertStringContainsString('&lt;a href=&quot;#&quot;', $sanitized['about_en'][0]);
        // Verify the dangerous onclick is escaped (quotes are converted to &quot;)
        $this->assertStringContainsString('onclick=&quot;', $sanitized['about_en'][0]);
    }

    /**
     * Test that data URIs with JavaScript are escaped.
     *
     * @return void
     */
    public function test_search_highlights_escape_data_uris()
    {
        $user = User::factory()->create();
        $this->actingAs($user);

        $component = new MainSearchBar();
        $reflection = new \ReflectionClass($component);
        $method = $reflection->getMethod('sanitizeHighlights');
        $method->setAccessible(true);

        $maliciousHighlights = [
            'about_en' => [
                'Visit <a href="data:text/html,<script>alert(1)</script>">link</a>'
            ]
        ];

        $sanitized = $method->invoke($component, $maliciousHighlights);

        // The anchor tag should be escaped, making the data URI harmless
        $this->assertStringNotContainsString('<a href="data:text/html', $sanitized['about_en'][0]);
        $this->assertStringContainsString('&lt;a', $sanitized['about_en'][0]);
        // Verify the script tag within the data URI is also escaped
        $this->assertStringContainsString('&lt;script&gt;', $sanitized['about_en'][0]);
    }
}
