<?php

namespace App\Tests\Appointment;

use App\Appointment\Entity\Appointment;
use App\Appointment\Entity\WeeklySchedule;
use App\Appointment\Service\SlotCalculatorService;
use App\Doctor\Entity\Doctor;
use App\Tests\ApiTestCase;

/**
 * حالت نوبت‌دهی سرویسی: getServiceStartTimes باید فضای خالیِ داخل شیفت را با توجه
 * به مدت سرویس (+ بافر) بچیند و بازه‌های اشغال‌شده را رد کند. همچنین متای mode/buffer.
 */
class ServiceBasedSlotsTest extends ApiTestCase
{
    private function makeDoctorWithServiceSchedule(int $buffer = 5): array
    {
        $owner  = $this->createUser(['ROLE_DOCTOR']);
        $doctor = new Doctor($owner, 'دکتر سرویس');
        $this->em->persist($doctor);

        // فردا در بازهٔ booking-window قرار دارد و روز گذشته نیست.
        $date   = date('Y-m-d', strtotime('tomorrow'));
        $dayKey = (string)(((int) date('w', strtotime($date)) + 1) % 7);

        $schedule = $this->newWeeklySchedule($doctor, [
            $dayKey => ['sessions' => [[
                'active'               => true,
                'start_time'           => '15:00',
                'end_time'             => '17:00',
                'duration_per_patient' => 20,
                'location_id'          => 1,
            ]]],
        ]);
        $schedule->setMeta(['booking_mode' => WeeklySchedule::MODE_SERVICE, 'buffer_minutes' => $buffer]);
        $this->em->persist($schedule);
        $this->em->flush();

        return [$doctor, $date];
    }

    public function testGapPackingWithBuffer(): void
    {
        [$doctor, $date] = $this->makeDoctorWithServiceSchedule(5);

        $calc  = static::getContainer()->get(SlotCalculatorService::class);
        $slots = $calc->getServiceStartTimes($doctor, $date, 30);

        // پنجره 15:00–17:00، سرویس 30 + بافر 5 → گام 35 دقیقه: 15:00, 15:35, 16:10
        $times = array_column($slots, 'start_time');
        $this->assertSame(['15:00', '15:35', '16:10'], $times);

        // زمان پایانِ ذخیره‌شده بدون بافر است.
        $this->assertSame(strtotime($date . ' 15:00') + 30 * 60, $slots[0]['end']);
    }

    public function testBookedIntervalIsSkipped(): void
    {
        [$doctor, $date] = $this->makeDoctorWithServiceSchedule(5);

        $patient = $this->createUser(['ROLE_USER']);
        $start   = strtotime($date . ' 15:00');
        $appt    = $this->newAppointment($doctor, $patient, $start, $start + 30 * 60);
        $appt->transitionTo(Appointment::STATUS_CONFIRMED);
        $this->em->persist($appt);
        $this->em->flush();

        $calc  = static::getContainer()->get(SlotCalculatorService::class);
        $times = array_column($calc->getServiceStartTimes($doctor, $date, 30), 'start_time');

        // 15:00 اشغال است → از 15:30 شروع می‌شود.
        $this->assertNotContains('15:00', $times);
        $this->assertContains('15:30', $times);
    }

    public function testNoRoomReturnsEmpty(): void
    {
        [$doctor, $date] = $this->makeDoctorWithServiceSchedule(0);

        // سرویس 200 دقیقه در پنجرهٔ 120 دقیقه‌ای جا نمی‌شود.
        $calc = static::getContainer()->get(SlotCalculatorService::class);
        $this->assertSame([], $calc->getServiceStartTimes($doctor, $date, 200));
    }

    public function testMetaDefaultsAndWhitelist(): void
    {
        $owner  = $this->createUser(['ROLE_DOCTOR']);
        $doctor = new Doctor($owner, 'دکتر متا');
        $schedule = $this->newWeeklySchedule($doctor, []);

        // پیش‌فرض = اسلاتی
        $this->assertSame(WeeklySchedule::MODE_SLOT, $schedule->getMeta()['booking_mode']);
        $this->assertSame(0, $schedule->getMeta()['buffer_minutes']);

        $schedule->setMeta(['booking_mode' => 'service', 'buffer_minutes' => 7]);
        $this->assertSame('service', $schedule->getMeta()['booking_mode']);
        $this->assertSame(7, $schedule->getMeta()['buffer_minutes']);

        // مقدار نامعتبر mode نادیده گرفته می‌شود (whitelist)، بافر منفی → صفر.
        $schedule->setMeta(['booking_mode' => 'bogus', 'buffer_minutes' => -3]);
        $this->assertSame('service', $schedule->getMeta()['booking_mode']);
        $this->assertSame(0, $schedule->getMeta()['buffer_minutes']);
    }
}
