<?php

namespace App\Tests\Twig;

use App\Twig\ViteAssetExtension;
use PHPUnit\Framework\TestCase;
use Psr\Cache\CacheItemInterface;
use Psr\Cache\CacheItemPoolInterface;

class ViteAssetExtensionTest extends TestCase
{
    private string $manifestPath;
    private CacheItemPoolInterface $cache;

    protected function setUp(): void
    {
        $this->manifestPath = sys_get_temp_dir().'/manifest.json';
        $this->cache = $this->createStub(CacheItemPoolInterface::class);
    }

    protected function tearDown(): void
    {
        if (file_exists($this->manifestPath)) {
            @unlink($this->manifestPath);
        }
    }

    public function testGetFunctions(): void
    {
        $_ENV['VITE_LOAD'] = '1';
        $extension = new ViteAssetExtension($this->manifestPath, $this->cache);
        $functions = $extension->getFunctions();

        $this->assertCount(3, $functions);
        $this->assertEquals('vite_asset', $functions[0]->getName());
        $this->assertEquals('isMobile', $functions[1]->getName());
        $this->assertEquals('vite_favicons', $functions[2]->getName());
    }

    public function testIsMobile(): void
    {
        $_ENV['VITE_LOAD'] = '1';
        $extension = new ViteAssetExtension($this->manifestPath, $this->cache);
        $this->assertIsBool($extension->isMobile());
    }

    public function testAssetDev(): void
    {
        $_ENV['VITE_LOAD'] = '0';

        $extension = new class($this->manifestPath, $this->cache) extends ViteAssetExtension {
            protected function getNonce(): string
            {
                return 'fake-nonce';
            }
        };

        $html = $extension->asset('app.js');

        $this->assertStringContainsString('http://localhost:5173/assets/app.js', $html);
        $this->assertStringContainsString('nonce="fake-nonce"', $html);
    }

    public function testAssetProdWithCacheHit(): void
    {
        $_ENV['VITE_LOAD'] = '1';
        $item = $this->createStub(CacheItemInterface::class);
        $item->method('isHit')->willReturn(true);
        $item->method('get')->willReturn(['app.js' => ['file' => 'app.123.js', 'css' => ['app.123.css']]]);

        $this->cache->method('getItem')->willReturn($item);

        $extension = new ViteAssetExtension($this->manifestPath, $this->cache);
        $html = $extension->asset('app.js');

        $this->assertStringContainsString('/build/app.123.js', $html);
        $this->assertStringContainsString('/build/app.123.css', $html);
    }

    public function testAssetProdWithCacheMissAndMissingFile(): void
    {
        $_ENV['VITE_LOAD'] = '1';
        $item = $this->createStub(CacheItemInterface::class);
        $item->method('isHit')->willReturn(false);
        $this->cache->method('getItem')->willReturn($item);

        if (file_exists($this->manifestPath)) {
            @unlink($this->manifestPath);
        }

        $extension = new ViteAssetExtension($this->manifestPath, $this->cache);
        $html = $extension->asset('app.js');

        $this->assertStringContainsString('/build/', $html);
    }

    public function testAssetProdWithCacheMissAndFileExists(): void
    {
        $_ENV['VITE_LOAD'] = '1';
        file_put_contents($this->manifestPath, json_encode(['app.js' => ['file' => 'app.456.js']]));

        $item = $this->createMock(CacheItemInterface::class);
        $item->method('isHit')->willReturn(false);
        $item->expects($this->once())->method('set');

        $cache = $this->createMock(CacheItemPoolInterface::class);
        $cache->method('getItem')->willReturn($item);
        $cache->expects($this->once())->method('save');

        $extension = new ViteAssetExtension($this->manifestPath, $cache);
        $html = $extension->asset('app.js');

        $this->assertStringContainsString('/build/app.456.js', $html);
    }

    public function testFaviconsDev(): void
    {
        $_ENV['VITE_LOAD'] = '0';
        $extension = new ViteAssetExtension($this->manifestPath, $this->cache);
        $html = $extension->favicons();

        $this->assertEquals('<link rel="icon" href="/favicon.ico">', $html);
    }

    public function testFaviconsProd(): void
    {
        $_ENV['VITE_LOAD'] = '1';
        $item = $this->createStub(CacheItemInterface::class);
        $item->method('isHit')->willReturn(true);
        $item->method('get')->willReturn([
            'favicon.png' => ['file' => 'favicon.789.png'],
            'app.js' => ['file' => 'app.js'],
        ]);
        $this->cache->method('getItem')->willReturn($item);

        $extension = new ViteAssetExtension($this->manifestPath, $this->cache);
        $html = $extension->favicons();

        $this->assertStringContainsString('/build/favicon.789.png', $html);
        $this->assertStringNotContainsString('app.js', $html);
    }
}
