<?php

namespace Tests\Unit;

use App\Services\ComponentScannerService;
use App\Models\Component;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Support\Facades\Cache;
use Tests\TestCase;

class ComponentScannerServiceTest extends TestCase
{
    private ComponentScannerService $scannerService;

    protected function setUp(): void
    {
        parent::setUp();
        $this->scannerService = new ComponentScannerService();
    }

    /**
     * Test component discovery returns array structure
     */
    public function test_discover_components_returns_correct_structure()
    {
        $result = $this->scannerService->discoverComponents();

        $this->assertIsArray($result);
        $this->assertArrayHasKey('components', $result);
        $this->assertArrayHasKey('categories', $result);
        $this->assertIsArray($result['components']);
        $this->assertIsArray($result['categories']);
    }

    /**
     * Test component model creation from file path
     */
    public function test_component_model_creation()
    {
        $absolutePath = '/test/path/newsletter_form.twig';
        $relativePath = 'pages/newsletter/newsletter_form.twig';

        $component = Component::fromFilePath($absolutePath, $relativePath);

        $this->assertInstanceOf(Component::class, $component);
        $this->assertEquals('Newsletter Form', $component->name);
        $this->assertEquals('newsletter_form.twig', $component->filename);
        $this->assertEquals('pages/newsletter/newsletter_form.twig', $component->path);
        $this->assertEquals('pages/newsletter', $component->category);
        $this->assertStringContains('Newsletter Form component', $component->description);
    }

    /**
     * Test name generation from filename
     */
    public function test_name_generation()
    {
        $testCases = [
            'newsletter_form.twig' => 'Newsletter Form',
            'user-profile.twig' => 'User Profile',
            'simple.twig' => 'Simple',
            'multi_word_component.twig' => 'Multi Word Component',
        ];

        foreach ($testCases as $filename => $expected) {
            $result = Component::generateName($filename);
            $this->assertEquals($expected, $result);
        }
    }

    /**
     * Test category extraction from path
     */
    public function test_category_extraction()
    {
        $testCases = [
            'pages/newsletter/form.twig' => 'pages/newsletter',
            'forms/contact.twig' => 'forms',
            'simple.twig' => 'general',
            'navigation/menu/main.twig' => 'navigation/menu',
        ];

        foreach ($testCases as $path => $expected) {
            $result = Component::extractCategory($path);
            $this->assertEquals($expected, $result);
        }
    }

    /**
     * Test description generation
     */
    public function test_description_generation()
    {
        $result = Component::generateDescription('Newsletter Form', 'pages/newsletter');

        $this->assertIsString($result);
        $this->assertStringContains('Newsletter Form', $result);
        $this->assertStringContains('component', $result);
    }

    /**
     * Test caching functionality
     */
    public function test_caching_functionality()
    {
        // Clear cache first
        $this->scannerService->clearCache();

        // First call should create cache
        $result1 = $this->scannerService->discoverComponents();

        // Second call should use cache (this is hard to test directly,
        // but we can verify the results are consistent)
        $result2 = $this->scannerService->discoverComponents();

        $this->assertEquals($result1, $result2);
    }

    /**
     * Test component search functionality
     */
    public function test_component_search()
    {
        // This test assumes there are components to search
        $results = $this->scannerService->searchComponents('test');

        $this->assertIsArray($results);

        // Each result should be a Component instance
        foreach ($results as $component) {
            $this->assertInstanceOf(Component::class, $component);
        }
    }

    /**
     * Test component filtering by category
     */
    public function test_component_filtering_by_category()
    {
        // This test assumes there are components to filter
        $results = $this->scannerService->getComponentsByCategory('pages');

        $this->assertIsArray($results);

        // All results should belong to the 'pages' category
        foreach ($results as $component) {
            $this->assertInstanceOf(Component::class, $component);
            $this->assertStringStartsWith('pages', $component->category);
        }
    }

    /**
     * Test error handling for non-existent component
     */
    public function test_find_non_existent_component()
    {
        $component = $this->scannerService->findComponent('non/existent/component.twig');

        $this->assertNull($component);
    }

    /**
     * Test cache clearing
     */
    public function test_cache_clearing()
    {
        // Create cache entry
        $this->scannerService->discoverComponents();

        // Clear cache
        $this->scannerService->clearCache();

        // This test passes if no exceptions are thrown
        $this->assertTrue(true);
    }

    /**
     * Test component array conversion
     */
    public function test_component_array_conversion()
    {
        $component = Component::fromFilePath('/test/path/test.twig', 'test.twig');
        $array = $component->toArray();

        $this->assertIsArray($array);
        $this->assertArrayHasKey('name', $array);
        $this->assertArrayHasKey('filename', $array);
        $this->assertArrayHasKey('path', $array);
        $this->assertArrayHasKey('category', $array);
        $this->assertArrayHasKey('description', $array);
        $this->assertArrayHasKey('file_size', $array);
        $this->assertArrayHasKey('modified_at', $array);
        $this->assertArrayHasKey('is_renderable', $array);
    }

    /**
     * Test component error marking
     */
    public function test_component_error_marking()
    {
        $component = Component::fromFilePath('/test/path/test.twig', 'test.twig');

        $this->assertTrue($component->is_renderable);
        $this->assertNull($component->error_message);

        $component->markAsError('Test error');

        $this->assertFalse($component->is_renderable);
        $this->assertEquals('Test error', $component->error_message);
    }
}