<?php

namespace App\Tests\Appointment;

use App\ClinicService\Entity\ServiceItem;
use App\ClinicService\Entity\ServiceSection;
use App\Doctor\Entity\Doctor;
use App\Tests\ApiTestCase;

/**
 * فیلدهای سرویسیِ نوبت: جایگزینی کامل سرویس‌ها، هم‌گامی ستون تکیِ `serviceItem`، و
 * مدت/بافرِ ثبت‌شده در لحظهٔ ثبت.
 */
class AppointmentServiceFieldsTest extends ApiTestCase
{
    private function doctorWithServices(int $count): array
    {
        $owner  = $this->createUser(['ROLE_DOCTOR']);
        $doctor = new Doctor($owner, 'دکتر فیلدهای سرویسی');
        $this->em->persist($doctor);
        // بخش به شناسهٔ پزشک نیاز دارد، پس پزشک باید پیش از ساختش flush شود.
        $this->em->flush();

        $section = new ServiceSection('doctor', $doctor->getId(), 'بخش تست');
        $this->em->persist($section);

        $items = [];
        for ($i = 1; $i <= $count; $i++) {
            $item = new ServiceItem($section, 'سرویس ' . $i, 0);
            $item->setDurationMinutes(10 * $i)->setBookable(true);
            $this->em->persist($item);
            $items[] = $item;
        }
        $this->em->flush();

        return [$doctor, $items];
    }

    private function appointmentFor(Doctor $doctor): \App\Appointment\Entity\Appointment
    {
        $patient = $this->createUser(['ROLE_USER']);
        $start   = strtotime('+5 days 10:00');

        return $this->newAppointment($doctor, $patient, $start, $start + 1800);
    }

    // ── ✅ موفق ──────────────────────────────────────────────────────────────

    public function testReplaceServiceItemsSyncsTheLegacySingleColumn(): void
    {
        [$doctor, $items] = $this->doctorWithServices(3);
        $appt = $this->appointmentFor($doctor);

        $appt->replaceServiceItems([$items[0], $items[1]]);
        self::assertCount(2, $appt->getServiceItems());
        self::assertSame($items[0], $appt->getServiceItem(), 'سرویس تکی = اولین عضو');

        // جایگزینی کامل: اعضای قبلی می‌روند و تکی هم به‌روز می‌شود.
        $appt->replaceServiceItems([$items[2]]);
        self::assertCount(1, $appt->getServiceItems());
        self::assertSame($items[2], $appt->getServiceItem(), 'تکی باید با عضو جدید هم‌گام شود');
    }

    public function testCurrentServiceUuidsKeepsInputOrder(): void
    {
        [$doctor, $items] = $this->doctorWithServices(3);
        $appt = $this->appointmentFor($doctor);

        $appt->replaceServiceItems([$items[2], $items[0], $items[1]]);

        self::assertSame(
            [$items[2]->getUuid(), $items[0]->getUuid(), $items[1]->getUuid()],
            $appt->currentServiceUuids(),
        );
    }

    public function testSetServiceDurationIsExposedInToArray(): void
    {
        [$doctor] = $this->doctorWithServices(1);
        $appt = $this->appointmentFor($doctor);

        $appt->setServiceDuration(45, 10);

        self::assertSame(45, $appt->getServiceTotalMinutes());
        self::assertSame(10, $appt->getServiceBufferMinutes());

        $array = $appt->toArray();
        self::assertSame(45, $array['service_total_minutes']);
        self::assertSame(10, $array['service_buffer_minutes']);
    }

    // ── ❌ خطا / مسیر نادرست ─────────────────────────────────────────────────

    public function testReplaceWithEmptyListClearsTheLegacySingleColumn(): void
    {
        [$doctor, $items] = $this->doctorWithServices(2);
        $appt = $this->appointmentFor($doctor);
        $appt->replaceServiceItems([$items[0]]);

        $appt->replaceServiceItems([]);

        self::assertCount(0, $appt->getServiceItems());
        self::assertNull($appt->getServiceItem(), 'سرویس تکی نباید یادگارِ انتخاب قبلی بماند');
        self::assertSame([], $appt->currentServiceUuids());
    }

    // ── ⚠️ مرزی ──────────────────────────────────────────────────────────────

    public function testSlotModeAppointmentKeepsBothColumnsNull(): void
    {
        [$doctor] = $this->doctorWithServices(1);
        $appt = $this->appointmentFor($doctor);

        self::assertNull($appt->getServiceTotalMinutes());
        self::assertNull($appt->getServiceBufferMinutes());
        self::assertNull($appt->toArray()['service_total_minutes']);
    }

    public function testClearingDurationAlsoClearsBuffer(): void
    {
        [$doctor] = $this->doctorWithServices(1);
        $appt = $this->appointmentFor($doctor);
        $appt->setServiceDuration(45, 10);

        // بافرِ بی‌مدت معنا ندارد؛ حتی اگر مقدار بافر پاس داده شود باید NULL شود.
        $appt->setServiceDuration(null, 10);

        self::assertNull($appt->getServiceTotalMinutes());
        self::assertNull($appt->getServiceBufferMinutes());
    }

    public function testDuplicateItemsInReplaceAreDeduplicated(): void
    {
        [$doctor, $items] = $this->doctorWithServices(1);
        $appt = $this->appointmentFor($doctor);

        $appt->replaceServiceItems([$items[0], $items[0]]);

        self::assertCount(1, $appt->getServiceItems());
    }

    public function testLegacyAppointmentWithOnlySingleItemStillReportsItsUuid(): void
    {
        [$doctor, $items] = $this->doctorWithServices(1);
        $appt = $this->appointmentFor($doctor);

        // نوبت پیش از چند-سرویسی‌شدن: فقط ستون تکی پر است.
        $appt->setServiceItem($items[0]);

        self::assertCount(0, $appt->getServiceItems());
        self::assertSame([$items[0]->getUuid()], $appt->currentServiceUuids());
    }

    public function testReplacePersistsThroughFlush(): void
    {
        [$doctor, $items] = $this->doctorWithServices(2);
        $appt = $this->appointmentFor($doctor);
        $appt->replaceServiceItems([$items[0], $items[1]])->setServiceDuration(30, 5);
        $this->em->persist($appt);
        $this->em->flush();
        $this->em->clear();

        $reloaded = static::getContainer()
            ->get(\App\Appointment\Repository\AppointmentRepository::class)
            ->findByUuid($appt->getUuid());

        self::assertNotNull($reloaded);
        self::assertCount(2, $reloaded->getServiceItems());
        self::assertSame(30, $reloaded->getServiceTotalMinutes());
        self::assertSame(5, $reloaded->getServiceBufferMinutes());
    }
}
