<?php

declare(strict_types=1);

namespace App\Tests\Integration\Command;

use App\Entity\Device;
use App\Entity\Image;
use App\Entity\RenderedAsset;
use App\Enum\DeviceModel;
use App\Enum\Orientation;
use App\Enum\RenderStatus;
use App\Tests\AppKernelTestCase;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Console\Tester\CommandTester;

/**
 * The rerender command is the operational lever for "renderer changed,
 * regenerate every existing asset." A regression here would silently leave
 * old bins on disk after a renderer bump, so end users see stale colors
 * with no indication anything's wrong.
 */
class RerenderAssetsCommandTest extends AppKernelTestCase
{
    private function commandTester(): CommandTester
    {
        $kernel = self::bootKernel();
        $app = new Application($kernel);
        return new CommandTester($app->find('app:rerender-assets'));
    }

    public function test_resets_ready_assets_to_pending_and_dispatches_render_messages(): void
    {
        $user = $this->createUser('rerender@example.com');
        $device = (new Device())
            ->setMac('AA:BB:CC:DD:EE:F0')
            ->setName('Frame')
            ->setUser($user)
            ->setModel(DeviceModel::V1)
            ->setOrientation(Orientation::Landscape);
        self::em()->persist($device);

        $image = (new Image())->setUser($user)->setOriginalFilename('a.jpg')->setStoragePath('a');
        self::em()->persist($image);

        $asset = (new RenderedAsset())
            ->setImage($image)
            ->setDeviceModel(DeviceModel::V1)
            ->setOrientation(Orientation::Landscape)
            ->setStatus(RenderStatus::Ready)
            ->setFilePath('var/storage/x.bin');
        self::em()->persist($asset);
        self::em()->flush();

        $tester = $this->commandTester();
        $exit = $tester->execute([]);
        $this->assertSame(0, $exit);
        $this->assertStringContainsString('Reset and re-dispatched 1 rendered assets', $tester->getDisplay());

        self::em()->clear();
        $reloaded = self::em()->find(RenderedAsset::class, $asset->getId());
        $this->assertSame(RenderStatus::Pending, $reloaded->getStatus());
        $this->assertNull($reloaded->getFilePath());

        // The in-memory transport doesn't reliably retain messages dispatched
        // from CommandTester across the kernel boundary, so we verify the
        // dispatch indirectly: a fresh asset was reset (filePath cleared,
        // Pending status), which only happens on the path that ALSO calls
        // $bus->dispatch(). The reset wouldn't be flushed if the dispatch
        // had thrown.
    }

    public function test_no_assets_means_no_messages_dispatched(): void
    {
        $tester = $this->commandTester();
        $exit = $tester->execute([]);
        $this->assertSame(0, $exit);
        $this->assertStringContainsString('Reset and re-dispatched 0 rendered assets', $tester->getDisplay());
    }
}
