<?php

namespace App\Tests\Command;

use App\Command\AppWarmupImagesCommand;
use App\Repository\OptionsRepository;
use App\Repository\ProductRepository;
use Liip\ImagineBundle\Binary\BinaryInterface;
use Liip\ImagineBundle\Imagine\Cache\CacheManager;
use Liip\ImagineBundle\Imagine\Data\DataManager;
use Liip\ImagineBundle\Imagine\Filter\FilterManager;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Tester\CommandTester;
use Vich\UploaderBundle\Storage\StorageInterface;

class AppWarmupImagesCommandTest extends TestCase
{
    public function testExecute()
    {
        // Mocks
        $productRepo = $this->createStub(ProductRepository::class);
        $optionsRepo = $this->createStub(OptionsRepository::class);
        $cacheManager = $this->createMock(CacheManager::class);
        $dataManager = $this->createMock(DataManager::class);
        $filterManager = $this->createMock(FilterManager::class);
        $storage = $this->createStub(StorageInterface::class);
        $binary = $this->createStub(BinaryInterface::class);

        // Dummy data
        $product = new \stdClass();
        $option = new \stdClass();

        $productRepo->method('findAll')->willReturn([$product]);
        $optionsRepo->method('findAll')->willReturn([$option]);

        // Helper behavior
        $storage->method('resolveUri')
            ->willReturnMap([
                [$product, 'imageFile', null, '/uploads/product.jpg'],
                [$option, 'imageFile', null, '/uploads/option.jpg'],
            ]);

        // Note: resolveUri signature is (obj, fieldName, className). willReturnMap matches arguments exactly.
        // We need to be careful with arguments.
        // The command calls: $this->storage->resolveUri($entity, $fieldName);
        // So arguments are: $entity, $fieldName. The third argument is optional (null default).
        // PHPUnit willReturnMap might be strict about argument count or we can use `with` and `willReturn`.

        // Let's use `willReturnCallback` or just simpler `willReturn` if we don't care about args,
        // but we want distinct return values.

        $storage->method('resolveUri')
            ->willReturnCallback(function($entity, $field) use ($product, $option) {
                if ($entity === $product && $field === 'imageFile') return '/uploads/product.jpg';
                if ($entity === $option && $field === 'imageFile') return '/uploads/option.jpg';
                return null;
            });

        // Filters defined in Command (must match private const FILTERS)
        $filters = ['webp', 'logo', 'product_card', 'poster_hero'];
        $filtersCount = count($filters);

        // 2 entities * 4 filters = 8 operations
        $cacheManager->expects($this->exactly(2 * $filtersCount))->method('remove');
        $dataManager->expects($this->exactly(2 * $filtersCount))->method('find')->willReturn($binary);
        $filterManager->expects($this->exactly(2 * $filtersCount))->method('applyFilter')->willReturn($binary);
        $cacheManager->expects($this->exactly(2 * $filtersCount))->method('store');

        // Instantiate Command
        $command = new AppWarmupImagesCommand(
            $productRepo,
            $optionsRepo,
            $cacheManager,
            $dataManager,
            $filterManager,
            $storage
        );

        $application = new Application();
        $application->addCommand($command);

        $command = $application->find('app:images:warmup');
        $commandTester = new CommandTester($command);

        $commandTester->execute([]);

        $commandTester->assertCommandIsSuccessful();

        $output = $commandTester->getDisplay();
        $this->assertStringContainsString('Régénération FORCÉE du cache LiipImagine', $output);
        $this->assertStringContainsString('Toutes les images ont été régénérées avec succès.', $output);
    }
}
