<?php

declare(strict_types=1);

namespace App\Command;

use App\Entity\Device;
use App\Entity\User;
use App\Enum\DeviceModel;
use App\Enum\Orientation;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

/**
 * Seeds fake devices on a user account so the multi-frame UI can be
 * exercised without provisioning real hardware. Each fake gets a MAC in
 * the AA:BB:CC:DD:EE:** range so the command can clean them up on re-run
 * without touching real devices.
 *
 *   docker exec pictureframe-php-1 php bin/console app:seed-fake-devices user@example.com
 *   docker exec pictureframe-php-1 php bin/console app:seed-fake-devices user@example.com --remove
 */
#[AsCommand(
    name: 'app:seed-fake-devices',
    description: 'Seed fake devices on a user account for UI testing',
)]
final class SeedFakeDevicesCommand extends Command
{
    private const FAKE_MAC_PREFIX = 'AA:BB:CC:DD:EE:';

    public function __construct(
        private readonly EntityManagerInterface $em,
    ) {
        parent::__construct();
    }

    protected function configure(): void
    {
        $this
            ->addArgument('email', InputArgument::REQUIRED, 'Account email')
            ->addOption('remove', null, InputOption::VALUE_NONE, 'Remove previously-seeded fake devices and exit');
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io    = new SymfonyStyle($input, $output);
        $email = (string) $input->getArgument('email');

        $user = $this->em->getRepository(User::class)->findOneBy(['email' => $email]);
        if ($user === null) {
            $io->error("No user found with email '$email'.");
            return Command::FAILURE;
        }

        // Always sweep prior fakes first (re-runs stay idempotent).
        $existing = $this->em->getRepository(Device::class)->createQueryBuilder('d')
            ->where('d.user = :u AND d.mac LIKE :prefix')
            ->setParameter('u', $user)
            ->setParameter('prefix', self::FAKE_MAC_PREFIX . '%')
            ->getQuery()
            ->getResult();
        foreach ($existing as $d) {
            $this->em->remove($d);
        }
        if ($existing) {
            $this->em->flush();
            $io->writeln(sprintf('Removed %d existing fake device(s).', count($existing)));
        }

        if ($input->getOption('remove')) {
            $io->success('Done.');
            return Command::SUCCESS;
        }

        // Five fakes covering each status state.
        $now   = new \DateTimeImmutable();
        $fakes = [
            ['name' => 'Living Room', 'orientation' => Orientation::Landscape, 'lastSeen' => 'PT5M',  'wakeTimes' => []],
            ['name' => 'Kitchen',     'orientation' => Orientation::Landscape, 'lastSeen' => 'PT90M', 'wakeTimes' => []],
            ['name' => 'Bedroom',     'orientation' => Orientation::Portrait,  'lastSeen' => 'P3D',   'wakeTimes' => []],
            ['name' => "Mom's Place", 'orientation' => Orientation::Portrait,  'lastSeen' => null,    'wakeTimes' => []],
            ['name' => 'Cabin',       'orientation' => Orientation::Landscape, 'lastSeen' => 'PT1H',  'wakeTimes' => [4 * 60]],
        ];

        $reflLastSeen = new \ReflectionProperty(Device::class, 'lastSeenAt');
        $reflLastSeen->setAccessible(true);

        foreach ($fakes as $i => $cfg) {
            $device = new Device();
            $device->setMac(sprintf(self::FAKE_MAC_PREFIX . '%02X', $i + 1));
            $device->setName($cfg['name']);
            $device->setModel(DeviceModel::V1);
            $device->setOrientation($cfg['orientation']);
            $device->setRotationIntervalMinutes(60);
            $device->setTimezone('America/New_York');
            $device->setUser($user);
            if (!empty($cfg['wakeTimes'])) {
                $device->setWakeTimes($cfg['wakeTimes']);
            }
            if ($cfg['lastSeen'] !== null) {
                $reflLastSeen->setValue($device, $now->sub(new \DateInterval($cfg['lastSeen'])));
            }
            $this->em->persist($device);

            $io->writeln(sprintf(
                '  + %s — %s, %s',
                $cfg['name'],
                $cfg['orientation']->value,
                $cfg['lastSeen'] === null ? 'never seen' : 'last seen ' . $cfg['lastSeen'] . ' ago',
            ));
        }

        $this->em->flush();
        $io->success(sprintf('Seeded %d fake devices for %s.', count($fakes), $email));
        return Command::SUCCESS;
    }
}
