<?php

namespace App\Tests\Appointment;

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

/**
 * چند سرویس روی یک نوبت: در حالت اسلاتی سرویس‌ها فقط پیوست می‌شوند و ساعت پایانِ
 * دستی حفظ می‌ماند؛ در حالت سرویسی (duration_from_services) slot_end از مجموع مدت
 * سرویس‌ها بازمحاسبه می‌شود.
 */
class AppointmentMultiServiceTest extends ApiTestCase
{
    private function doctor(): array
    {
        $owner  = $this->createUser(['ROLE_DOCTOR']);
        $doctor = new Doctor($owner, 'دکتر تست');
        $this->em->persist($doctor);
        $this->em->flush();

        return [$owner, $doctor];
    }

    private function serviceItem(Doctor $doctor, string $name, int $minutes): ServiceItem
    {
        $section = new ServiceSection('doctor', $doctor->getId(), 'بخش ' . $name);
        $this->em->persist($section);
        $item = new ServiceItem($section, $name, 500_000);
        $item->setDurationMinutes($minutes)->setBookable(true);
        $this->em->persist($item);
        $this->em->flush();

        return $item;
    }

    private function nationalCode(): string
    {
        return '00' . str_pad((string) random_int(0, 99_999_999), 8, '0', STR_PAD_LEFT);
    }

    private function body(Doctor $doctor, int $start, int $end, array $extra): array
    {
        return array_merge([
            'doctor_uuid'           => $doctor->getUuid(),
            'slot_start'            => $start,
            'slot_end'              => $end,
            'patient_mobile'        => '09' . str_pad((string) random_int(0, 999_999_999), 9, '0', STR_PAD_LEFT),
            'patient_name'          => 'بیمار تست',
            'patient_national_code' => $this->nationalCode(),
        ], $extra);
    }

    private function reload(string $uuid): Appointment
    {
        $this->em->clear();
        return $this->em->getRepository(Appointment::class)->findOneBy(['uuid' => $uuid]);
    }

    public function testSlotModeAttachesMultipleServicesAndKeepsManualEnd(): void
    {
        [$owner, $doctor] = $this->doctor();
        $a = $this->serviceItem($doctor, 'تزریق ژل', 30);
        $b = $this->serviceItem($doctor, 'کندلا', 20);

        $start = time() + 86_400 + random_int(0, 3_600) * 100;
        $end   = $start + 3_600; // ساعت پایانِ دستی: ۶۰ دقیقه

        $res = $this->authJson('POST', '/api/v1/my/appointment', $owner, $this->body($doctor, $start, $end, [
            'service_item_uuids' => [$a->getUuid(), $b->getUuid()],
        ]));
        self::assertSame(201, $this->responseCode());

        $appt = $this->reload($res['data']['uuid']);
        self::assertCount(2, $appt->getServiceItems());
        // ساعت پایان دست‌نخورده (بدون بازمحاسبه از مدت سرویس‌ها)
        self::assertSame($end, $appt->getSlotEnd());
        // سرویسِ اصلی = اولین سرویس
        self::assertSame($a->getUuid(), $appt->getServiceItem()?->getUuid());
    }

    public function testServiceModeRecomputesEndFromDurations(): void
    {
        [$owner, $doctor] = $this->doctor();
        $a = $this->serviceItem($doctor, 'تزریق ژل', 30);
        $b = $this->serviceItem($doctor, 'کندلا', 20);

        $start = time() + 86_400 + random_int(0, 3_600) * 100;

        $res = $this->authJson('POST', '/api/v1/my/appointment', $owner, $this->body($doctor, $start, $start + 60, [
            'service_item_uuids'     => [$a->getUuid(), $b->getUuid()],
            'duration_from_services' => true,
        ]));
        self::assertSame(201, $this->responseCode());

        $appt = $this->reload($res['data']['uuid']);
        self::assertCount(2, $appt->getServiceItems());
        // مجموع مدت ۳۰+۲۰=۵۰ دقیقه → slot_end بازمحاسبه‌شده
        self::assertSame($start + 50 * 60, $appt->getSlotEnd());
    }

    public function testUnknownServiceUuidIsRejected(): void
    {
        [$owner, $doctor] = $this->doctor();
        $start = time() + 86_400 + random_int(0, 3_600) * 100;

        $this->authJson('POST', '/api/v1/my/appointment', $owner, $this->body($doctor, $start, $start + 1_800, [
            'service_item_uuids' => ['no-such-uuid'],
        ]));
        self::assertSame(422, $this->responseCode());
    }
}
