<?php

declare(strict_types=1);

namespace App\Tests\Integration\Command;

use App\Entity\Device;
use App\Entity\User;
use App\Tests\AppKernelTestCase;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Console\Tester\CommandTester;

/**
 * The seed command is dev-only but the rotation pipeline relies on its
 * "5 devices in different sync states" output for visual UI checks.
 * If it silently breaks (e.g. an entity field rename), nobody catches it
 * for a week. This test exercises the create / remove / re-run paths.
 */
class SeedFakeDevicesCommandTest extends AppKernelTestCase
{
    private function commandTester(): CommandTester
    {
        $kernel = self::bootKernel();
        $app = new Application($kernel);
        return new CommandTester($app->find('app:seed-fake-devices'));
    }

    public function test_errors_when_email_does_not_match_a_user(): void
    {
        $tester = $this->commandTester();
        $exit = $tester->execute(['email' => 'nobody@example.com']);
        $this->assertSame(1, $exit);
        $this->assertStringContainsString('No user found', $tester->getDisplay());
    }

    public function test_creates_five_fake_devices_for_an_existing_user(): void
    {
        $user = $this->createUser('seed@example.com');

        $tester = $this->commandTester();
        $exit = $tester->execute(['email' => 'seed@example.com']);

        $this->assertSame(0, $exit);
        $this->assertStringContainsString('Seeded 5 fake devices', $tester->getDisplay());

        self::em()->clear();
        $reloaded = self::em()->getRepository(User::class)->findOneBy(['email' => 'seed@example.com']);
        $devices = self::em()->getRepository(Device::class)->findBy(['user' => $reloaded]);
        $this->assertCount(5, $devices);
        // The Cabin device gets wakeTimes=[4*60]; everything else is empty.
        $withWakeTimes = array_filter($devices, fn(Device $d) => !empty($d->getWakeTimes()));
        $this->assertCount(1, $withWakeTimes);
        $this->assertSame([4 * 60], reset($withWakeTimes)->getWakeTimes());
    }

    public function test_re_runs_are_idempotent_existing_fakes_get_swept(): void
    {
        $this->createUser('seed-rerun@example.com');
        $tester = $this->commandTester();

        $tester->execute(['email' => 'seed-rerun@example.com']);
        $tester->execute(['email' => 'seed-rerun@example.com']);

        // After two runs we should still have exactly five devices and the
        // second run's output mentions sweeping.
        $this->assertStringContainsString('Removed 5 existing fake device(s)', $tester->getDisplay());

        self::em()->clear();
        $user = self::em()->getRepository(User::class)->findOneBy(['email' => 'seed-rerun@example.com']);
        $devices = self::em()->getRepository(Device::class)->findBy(['user' => $user]);
        $this->assertCount(5, $devices);
    }

    public function test_remove_flag_sweeps_and_exits_without_creating(): void
    {
        $this->createUser('seed-rm@example.com');
        $tester = $this->commandTester();
        $tester->execute(['email' => 'seed-rm@example.com']);

        $exit = $tester->execute(['email' => 'seed-rm@example.com', '--remove' => true]);
        $this->assertSame(0, $exit);

        self::em()->clear();
        $user = self::em()->getRepository(User::class)->findOneBy(['email' => 'seed-rm@example.com']);
        $devices = self::em()->getRepository(Device::class)->findBy(['user' => $user]);
        $this->assertCount(0, $devices);
    }
}
