<?php

namespace App\Tests\Doctor;

use App\Auth\Entity\User;
use App\Doctor\Command\PurgeUnclaimedDoctorsCommand;
use App\Doctor\Entity\Doctor;
use Doctrine\DBAL\Connection;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Tester\CommandTester;

/**
 * `app:doctors:purge-unclaimed` فقط باید پزشکانِ ایمپورت‌شدهٔ claim‌نشده و کاربران
 * جانشینشان را حذف کند. این تست دو قرارداد بحرانی را قفل می‌کند: --dry-run هیچ‌چیز
 * نمی‌نویسد، و پزشکان claimed / با منبع دیگر هرگز پاک نمی‌شوند.
 */
class PurgeUnclaimedDoctorsCommandTest extends KernelTestCase
{
    private function tester(): CommandTester
    {
        return new CommandTester(
            (new Application(self::bootKernel()))->find('app:doctors:purge-unclaimed')
        );
    }

    private function makeDoctor(string $source, string $ownerStatus, int $userStatus = 0): Doctor
    {
        $em     = static::getContainer()->get('doctrine')->getManager();
        $mobile = ($userStatus === 0 ? 'imp_' : '09') . str_pad((string) random_int(0, 999_999_999), 9, '0', STR_PAD_LEFT);

        $user = new User($mobile);
        $user->setStatus($userStatus);
        $em->persist($user);

        $doctor = new Doctor($user, 'دکتر آزمون');
        $doctor->setSource($source);
        $doctor->setOwnerStatus($ownerStatus);
        $em->persist($doctor);
        $em->flush();

        return $doctor;
    }

    private function doctorExists(int $id): bool
    {
        $conn = static::getContainer()->get(Connection::class);

        return (bool) $conn->fetchOne('SELECT COUNT(*) FROM doctors WHERE id = ?', [$id]);
    }

    public function testDryRunDeletesNothing(): void
    {
        $doctor = $this->makeDoctor('irimc', 'unclaimed');
        $id     = $doctor->getId();

        $tester = $this->tester();
        $tester->execute([]);
        $tester->assertCommandIsSuccessful();

        $this->assertTrue($this->doctorExists($id), 'dry-run نباید پزشک را حذف کند');
    }

    public function testForceDeletesUnclaimedImportedDoctorAndSurrogate(): void
    {
        $doctor      = $this->makeDoctor('irimc', 'unclaimed');
        $id          = $doctor->getId();
        $surrogateId = $doctor->getUser()->getId();

        $tester = $this->tester();
        $tester->execute(['--force' => true]);
        $tester->assertCommandIsSuccessful();

        $conn = static::getContainer()->get(Connection::class);
        $this->assertFalse($this->doctorExists($id), 'پزشک claim‌نشده باید حذف شود');
        $this->assertFalse(
            (bool) $conn->fetchOne('SELECT COUNT(*) FROM users WHERE id = ?', [$surrogateId]),
            'کاربر جانشین یتیم باید حذف شود',
        );
    }

    /** برخلاف app:doctors:purge، این کامند روی prod قابل اجراست — ولی فقط با سوییچ صریح. */
    private function prodTester(): CommandTester
    {
        self::bootKernel();

        return new CommandTester(
            new PurgeUnclaimedDoctorsCommand(static::getContainer()->get(Connection::class), 'prod')
        );
    }

    public function testRefusesOnProdWithoutExplicitSwitch(): void
    {
        $doctor = $this->makeDoctor('irimc', 'unclaimed');

        $tester = $this->prodTester();
        $tester->execute(['--force' => true]);

        $this->assertSame(Command::FAILURE, $tester->getStatusCode());
        $this->assertStringContainsString('i-know-this-is-prod', $tester->getDisplay());
        $this->assertTrue($this->doctorExists($doctor->getId()), 'گاردِ prod نباید چیزی حذف کند');
    }

    public function testRunsOnProdWithExplicitSwitch(): void
    {
        $doctor = $this->makeDoctor('irimc', 'unclaimed');

        $tester = $this->prodTester();
        $tester->execute(['--force' => true, '--i-know-this-is-prod' => true]);

        $tester->assertCommandIsSuccessful();
        $this->assertFalse($this->doctorExists($doctor->getId()), 'با سوییچ صریح باید روی prod حذف کند');
    }

    public function testClaimedAndOtherSourceDoctorsSurvive(): void
    {
        $claimed = $this->makeDoctor('irimc', 'claimed', userStatus: 1);
        $manual  = $this->makeDoctor('manual', 'unclaimed');

        $this->tester()->execute(['--force' => true]);

        $this->assertTrue($this->doctorExists($claimed->getId()), 'پزشک claimed نباید حذف شود');
        $this->assertTrue($this->doctorExists($manual->getId()), 'منبع غیر irimc نباید با پیش‌فرض حذف شود');
    }
}
