<?php

declare(strict_types=1);

use App\Framework\Cache\Cache;
use App\Framework\Cache\CacheItem;
use App\Framework\Cache\CacheKey;
use App\Framework\Cache\CacheResult;
use App\Framework\Core\PathProvider;
use App\Framework\View\Caching\Analysis\CacheStrategy;
use App\Framework\View\Caching\Analysis\SmartTemplateAnalyzer;
use App\Framework\View\Loading\TemplateLoader;

describe('SmartTemplateAnalyzer', function () {
    beforeEach(function () {
        // Create test templates directory
        $this->testDir = '/home/michael/dev/michaelschiemer/tests/tmp/smart_analyzer_' . uniqid();
        if (!is_dir($this->testDir)) {
            mkdir($this->testDir, 0755, true);
        }

        // Create real PathProvider
        $this->pathProvider = new PathProvider($this->testDir);

        // Create mocked Cache
        $this->cache = Mockery::mock(Cache::class);
        $this->cache->shouldReceive('get')->andReturn(CacheResult::fromItems(CacheItem::miss(CacheKey::fromString('test'))));
        $this->cache->shouldReceive('set')->andReturn(true);
        $this->cache->shouldReceive('clear')->andReturn(true);

        // Create TemplateLoader with test directory as template path
        $this->loader = new TemplateLoader(
            pathProvider: $this->pathProvider,
            cache: $this->cache,
            templates: [],
            templatePath: '',  // Empty to use base path directly
            cacheEnabled: false
        );

        $this->analyzer = new SmartTemplateAnalyzer($this->loader);
    });

    afterEach(function () {
        Mockery::close();

        // Clean up test files
        if (is_dir($this->testDir)) {
            $files = new RecursiveIteratorIterator(
                new RecursiveDirectoryIterator($this->testDir, RecursiveDirectoryIterator::SKIP_DOTS),
                RecursiveIteratorIterator::CHILD_FIRST
            );
            foreach ($files as $file) {
                $file->isDir() ? rmdir($file->getRealPath()) : unlink($file->getRealPath());
            }
            rmdir($this->testDir);
        }
    });

    describe('analyze()', function () {
        it('recommends FULL_PAGE strategy for layouts with high static ratio', function () {
            $content = '<html><head><title>Site</title></head><body>Mostly static content here</body></html>';

            // Create template file
            $filePath = $this->testDir . '/layouts/main.view.php';
            $dir = dirname($filePath);
            if (!is_dir($dir)) {
                mkdir($dir, 0755, true);
            }
            file_put_contents($filePath, $content);

            $analysis = $this->analyzer->analyze('layouts/main');

            expect($analysis->recommendedStrategy)->toBe(CacheStrategy::FULL_PAGE);
            expect($analysis->cacheability->staticContentRatio)->toBeGreaterThan(0.8);
        });

        it('recommends COMPONENT strategy for component templates', function () {
            $content = '<button class="btn">{{ text }}</button>';

            // Create template file
            $filePath = $this->testDir . '/components/button.view.php';
            $dir = dirname($filePath);
            if (!is_dir($dir)) {
                mkdir($dir, 0755, true);
            }
            file_put_contents($filePath, $content);

            $analysis = $this->analyzer->analyze('components/button');

            expect($analysis->recommendedStrategy)->toBe(CacheStrategy::COMPONENT);
        });

        it('recommends COMPONENT strategy for partial templates', function () {
            $content = '<nav class="main-navigation"><ul class="nav-list">{{ navigation_items }}</ul></nav>';

            // Create template file
            $filePath = $this->testDir . '/partials/navigation.view.php';
            $dir = dirname($filePath);
            if (!is_dir($dir)) {
                mkdir($dir, 0755, true);
            }
            file_put_contents($filePath, $content);

            $analysis = $this->analyzer->analyze('partials/navigation');

            expect($analysis->recommendedStrategy)->toBe(CacheStrategy::COMPONENT);
        });

        it('recommends NO_CACHE for templates with user content', function () {
            $content = '<div>Welcome {{ user.name }}! <p>Your profile</p></div>';

            // Create template file
            $filePath = $this->testDir . '/pages/profile.view.php';
            $dir = dirname($filePath);
            if (!is_dir($dir)) {
                mkdir($dir, 0755, true);
            }
            file_put_contents($filePath, $content);

            $analysis = $this->analyzer->analyze('pages/profile');

            expect($analysis->recommendedStrategy)->toBe(CacheStrategy::NO_CACHE);
            expect($analysis->cacheability->hasUserSpecificContent)->toBeTrue();
        });

        it('detects CSRF tokens and adjusts cacheability score', function () {
            $content = '<form method="POST"><input type="hidden" name="_token" value="{{ csrf_token }}"></form>';

            // Create template file
            $filePath = $this->testDir . '/forms/contact.view.php';
            $dir = dirname($filePath);
            if (!is_dir($dir)) {
                mkdir($dir, 0755, true);
            }
            file_put_contents($filePath, $content);

            $analysis = $this->analyzer->analyze('forms/contact');

            // CSRF tokens detected but high static ratio (0.839) means still cacheable (0.839 - 0.2 = 0.639 > 0.5)
            expect($analysis->cacheability->hasCsrfTokens)->toBeTrue();
            expect($analysis->cacheability->getScore())->toBeGreaterThan(0.5);
        });

        it('detects timestamps and adjusts cacheability score', function () {
            $content = '<div>Current time: {{ now }}</div>';

            // Create template file
            $filePath = $this->testDir . '/widgets/clock.view.php';
            $dir = dirname($filePath);
            if (!is_dir($dir)) {
                mkdir($dir, 0755, true);
            }
            file_put_contents($filePath, $content);

            $analysis = $this->analyzer->analyze('widgets/clock');

            // Timestamps detected but high static ratio means still cacheable
            expect($analysis->cacheability->hasTimestamps)->toBeTrue();
            expect($analysis->cacheability->getScore())->toBeGreaterThan(0.5);
        });

        it('recommends NO_CACHE for templates with random elements', function () {
            $content = '<div>Random ID: {{ uuid }}</div>';

            // Create template file
            $filePath = $this->testDir . '/widgets/random.view.php';
            $dir = dirname($filePath);
            if (!is_dir($dir)) {
                mkdir($dir, 0755, true);
            }
            file_put_contents($filePath, $content);

            $analysis = $this->analyzer->analyze('widgets/random');

            expect($analysis->recommendedStrategy)->toBe(CacheStrategy::NO_CACHE);
            expect($analysis->cacheability->hasRandomElements)->toBeTrue();
        });

        it('recommends FRAGMENT strategy for medium cacheability templates', function () {
            $content = '<div class="content"><h1>Title</h1><p>Some content</p><span>{{ small_dynamic_part }}</span></div>';

            // Create template file
            $filePath = $this->testDir . '/pages/mixed.view.php';
            $dir = dirname($filePath);
            if (!is_dir($dir)) {
                mkdir($dir, 0755, true);
            }
            file_put_contents($filePath, $content);

            $analysis = $this->analyzer->analyze('pages/mixed');

            expect($analysis->recommendedStrategy)->toBe(CacheStrategy::FRAGMENT);
            expect($analysis->cacheability->getScore())->toBeGreaterThan(0.5);
        });

        it('creates fallback analysis when loader throws exception', function () {
            $analysis = $this->analyzer->analyze('missing/template');

            expect($analysis->recommendedStrategy)->toBe(CacheStrategy::NO_CACHE);
            expect($analysis->recommendedTtl)->toBe(0);
            expect($analysis->dependencies)->toBeEmpty();
        });

        it('adjusts TTL based on cacheability score', function () {
            $staticContent = '<html><body>All static content here</body></html>';

            // Create template file
            $filePath = $this->testDir . '/static/page.view.php';
            $dir = dirname($filePath);
            if (!is_dir($dir)) {
                mkdir($dir, 0755, true);
            }
            file_put_contents($filePath, $staticContent);

            $analysis = $this->analyzer->analyze('static/page');

            expect($analysis->recommendedTtl)->toBeGreaterThan(0);
        });
    });

    describe('getDependencies()', function () {
        it('finds @include directives', function () {
            $content = '@include("header") <div>Content</div> @include("footer")';

            // Create template file
            $filePath = $this->testDir . '/page/test.view.php';
            $dir = dirname($filePath);
            if (!is_dir($dir)) {
                mkdir($dir, 0755, true);
            }
            file_put_contents($filePath, $content);

            $deps = $this->analyzer->getDependencies('page/test');

            expect($deps)->toHaveKey('includes');
            expect($deps['includes'])->toContain('header');
            expect($deps['includes'])->toContain('footer');
        });

        it('finds <component> tags', function () {
            $content = '<component name="button" /> <component name="card" />';

            // Create template file
            $filePath = $this->testDir . '/page/test2.view.php';
            $dir = dirname($filePath);
            if (!is_dir($dir)) {
                mkdir($dir, 0755, true);
            }
            file_put_contents($filePath, $content);

            $deps = $this->analyzer->getDependencies('page/test2');

            expect($deps)->toHaveKey('components');
            expect($deps['components'])->toContain('button');
            expect($deps['components'])->toContain('card');
        });

        it('finds both includes and components', function () {
            $content = '@include("layout") <component name="nav" /> <component name="footer" />';

            // Create template file
            $filePath = $this->testDir . '/page/test3.view.php';
            $dir = dirname($filePath);
            if (!is_dir($dir)) {
                mkdir($dir, 0755, true);
            }
            file_put_contents($filePath, $content);

            $deps = $this->analyzer->getDependencies('page/test3');

            expect($deps)->toHaveKey('includes');
            expect($deps)->toHaveKey('components');
            expect($deps['includes'])->toContain('layout');
            expect($deps['components'])->toContain('nav');
        });

        it('returns empty array when no dependencies found', function () {
            $content = '<div>No dependencies here</div>';

            // Create template file
            $filePath = $this->testDir . '/page/simple.view.php';
            $dir = dirname($filePath);
            if (!is_dir($dir)) {
                mkdir($dir, 0755, true);
            }
            file_put_contents($filePath, $content);

            $deps = $this->analyzer->getDependencies('page/simple');

            expect($deps)->toBeEmpty();
        });

        it('returns empty array when loader throws exception', function () {
            $deps = $this->analyzer->getDependencies('page/error');

            expect($deps)->toBeEmpty();
        });
    });

    describe('getCacheability()', function () {
        it('detects user-specific content patterns', function () {
            $content = '{{ user.name }} {{ current_user.email }} {{ auth.role }}';

            // Create template file
            $filePath = $this->testDir . '/test/user.view.php';
            $dir = dirname($filePath);
            if (!is_dir($dir)) {
                mkdir($dir, 0755, true);
            }
            file_put_contents($filePath, $content);

            $score = $this->analyzer->getCacheability('test/user');

            expect($score->hasUserSpecificContent)->toBeTrue();
            expect($score->isCacheable())->toBeFalse();
        });

        it('detects CSRF token patterns', function () {
            $content = '{{ csrf_token }} {{ _token }}';

            // Create template file
            $filePath = $this->testDir . '/test/csrf.view.php';
            $dir = dirname($filePath);
            if (!is_dir($dir)) {
                mkdir($dir, 0755, true);
            }
            file_put_contents($filePath, $content);

            $score = $this->analyzer->getCacheability('test/csrf');

            expect($score->hasCsrfTokens)->toBeTrue();
            expect($score->isCacheable())->toBeFalse();
        });

        it('detects timestamp patterns', function () {
            $content = '{{ now }} {{ timestamp }} {{ date() }}';

            // Create template file
            $filePath = $this->testDir . '/test/time.view.php';
            $dir = dirname($filePath);
            if (!is_dir($dir)) {
                mkdir($dir, 0755, true);
            }
            file_put_contents($filePath, $content);

            $score = $this->analyzer->getCacheability('test/time');

            expect($score->hasTimestamps)->toBeTrue();
            expect($score->isCacheable())->toBeFalse();
        });

        it('detects random element patterns', function () {
            $content = '{{ random }} {{ rand() }} {{ uuid }}';

            // Create template file
            $filePath = $this->testDir . '/test/random.view.php';
            $dir = dirname($filePath);
            if (!is_dir($dir)) {
                mkdir($dir, 0755, true);
            }
            file_put_contents($filePath, $content);

            $score = $this->analyzer->getCacheability('test/random');

            expect($score->hasRandomElements)->toBeTrue();
            expect($score->isCacheable())->toBeFalse();
        });

        it('calculates high static content ratio for mostly static templates', function () {
            $content = '<div>Static content</div><p>More static content here with lots of text</p><section>Even more static HTML content</section>{{ small_dynamic }}';

            // Create template file
            $filePath = $this->testDir . '/test/static.view.php';
            $dir = dirname($filePath);
            if (!is_dir($dir)) {
                mkdir($dir, 0755, true);
            }
            file_put_contents($filePath, $content);

            $score = $this->analyzer->getCacheability('test/static');

            expect($score->staticContentRatio)->toBeGreaterThan(0.8);
            expect($score->isCacheable())->toBeTrue();
        });

        it('calculates low static content ratio for mostly dynamic templates', function () {
            $content = '{{ var1 }} {{ var2 }} {{ var3 }} {{ var4 }} <p>static</p>';

            // Create template file
            $filePath = $this->testDir . '/test/dynamic.view.php';
            $dir = dirname($filePath);
            if (!is_dir($dir)) {
                mkdir($dir, 0755, true);
            }
            file_put_contents($filePath, $content);

            $score = $this->analyzer->getCacheability('test/dynamic');

            expect($score->staticContentRatio)->toBeLessThan(0.5);
        });

        it('returns default score when loader throws exception', function () {
            $score = $this->analyzer->getCacheability('test/error');

            // Default CacheabilityScore has staticContentRatio = 0.0
            expect($score->staticContentRatio)->toBe(0.0);
            expect($score->hasUserSpecificContent)->toBeFalse();
            expect($score->hasCsrfTokens)->toBeFalse();
            expect($score->hasTimestamps)->toBeFalse();
            expect($score->hasRandomElements)->toBeFalse();
        });

        it('handles empty content gracefully', function () {
            // Create empty template file
            $filePath = $this->testDir . '/test/empty.view.php';
            $dir = dirname($filePath);
            if (!is_dir($dir)) {
                mkdir($dir, 0755, true);
            }
            file_put_contents($filePath, '');

            $score = $this->analyzer->getCacheability('test/empty');

            expect($score->staticContentRatio)->toBe(0.0);
        });
    });

    describe('integration scenarios', function () {
        it('correctly analyzes a typical blog post template', function () {
            $content = <<<HTML
<article class="post">
    <header>
        <h1>{{ post.title }}</h1>
        <time>{{ post.published_at }}</time>
    </header>
    <div class="content">
        {{ post.content }}
    </div>
    <footer>
        <p>Read more articles</p>
    </footer>
</article>
HTML;

            // Create template file
            $filePath = $this->testDir . '/blog/post.view.php';
            $dir = dirname($filePath);
            if (!is_dir($dir)) {
                mkdir($dir, 0755, true);
            }
            file_put_contents($filePath, $content);

            $analysis = $this->analyzer->analyze('blog/post');

            expect($analysis->cacheability->hasTimestamps)->toBeFalse();
            expect($analysis->recommendedStrategy)->toBe(CacheStrategy::FRAGMENT);
        });

        it('correctly analyzes a static landing page', function () {
            $content = <<<HTML
<html>
<head><title>Welcome</title></head>
<body>
    <header><h1>Welcome to our site</h1></header>
    <main>
        <section>Static marketing content</section>
        <section>More static content</section>
    </main>
    <footer>Copyright 2024</footer>
</body>
</html>
HTML;

            // Create template file
            $filePath = $this->testDir . '/pages/landing.view.php';
            $dir = dirname($filePath);
            if (!is_dir($dir)) {
                mkdir($dir, 0755, true);
            }
            file_put_contents($filePath, $content);

            $analysis = $this->analyzer->analyze('pages/landing');

            expect($analysis->recommendedStrategy)->toBe(CacheStrategy::FULL_PAGE);
            expect($analysis->cacheability->staticContentRatio)->toBeGreaterThan(0.9);
        });

        it('correctly analyzes a reusable button component', function () {
            $content = '<button class="btn btn-{{ variant }}">{{ text }}</button>';

            // Create template file
            $filePath = $this->testDir . '/components/button2.view.php';
            $dir = dirname($filePath);
            if (!is_dir($dir)) {
                mkdir($dir, 0755, true);
            }
            file_put_contents($filePath, $content);

            $analysis = $this->analyzer->analyze('components/button2');

            expect($analysis->recommendedStrategy)->toBe(CacheStrategy::COMPONENT);
            expect($analysis->recommendedTtl)->toBeGreaterThan(0);
        });

        it('correctly analyzes a form with CSRF protection', function () {
            $content = <<<HTML
<form method="POST" action="/submit">
    {{ csrf_token }}
    <input type="text" name="email" />
    <button type="submit">Submit</button>
</form>
HTML;

            // Create template file
            $filePath = $this->testDir . '/forms/contact2.view.php';
            $dir = dirname($filePath);
            if (!is_dir($dir)) {
                mkdir($dir, 0755, true);
            }
            file_put_contents($filePath, $content);

            $analysis = $this->analyzer->analyze('forms/contact2');

            // CSRF detected and high static ratio means still cacheable, recommends FULL_PAGE
            expect($analysis->cacheability->hasCsrfTokens)->toBeTrue();
            expect($analysis->cacheability->staticContentRatio)->toBeGreaterThan(0.8);
            expect($analysis->recommendedStrategy)->toBe(CacheStrategy::FULL_PAGE);
        });
    });
});
