<?php

namespace App\Tests\Dashboard;

use App\Appointment\Entity\Appointment;
use App\Clinic\Entity\Clinic;
use App\Doctor\Entity\Doctor;
use App\Tests\ApiTestCase;

/**
 * GET /api/v1/dashboard/{clinic,doctor} — chart series periods.
 *
 * «نمودار تعداد بیماران» is one Jalali month (day-by-day) and «میزان درآمد» is
 * one Jalali year (month-by-month); both default to the current Jalali period
 * and are overridable via patients_year / patients_month / revenue_year.
 */
class DashboardChartPeriodTest extends ApiTestCase
{
    /** @return array{0:int, 1:int} [jalaliYear, jalaliMonth] */
    private function currentJalali(): array
    {
        $cal = \IntlCalendar::createInstance(new \DateTimeZone('Asia/Tehran'), 'fa_IR@calendar=persian');

        return [$cal->get(\IntlCalendar::FIELD_YEAR), $cal->get(\IntlCalendar::FIELD_MONTH) + 1];
    }

    private function jalaliMonthLength(int $year, int $month): int
    {
        $cal = \IntlCalendar::createInstance(new \DateTimeZone('Asia/Tehran'), 'fa_IR@calendar=persian');
        $cal->set(\IntlCalendar::FIELD_YEAR, $year);
        $cal->set(\IntlCalendar::FIELD_MONTH, $month - 1);
        $cal->set(\IntlCalendar::FIELD_DAY_OF_MONTH, 1);

        return $cal->getActualMaximum(\IntlCalendar::FIELD_DAY_OF_MONTH);
    }

    private function clinicWithDoctor(): array
    {
        $clinicOwner = $this->createUser(['ROLE_CLINIC']);
        $clinic      = new Clinic($clinicOwner);
        $clinic->setName('کلینیک نمودار');

        $docOwner = $this->createUser(['ROLE_DOCTOR']);
        $doctor   = new Doctor($docOwner, 'حمیدی');
        $clinic->getDoctors()->add($doctor);

        $this->em->persist($doctor);
        $this->em->persist($clinic);
        $this->em->flush();

        return [$clinicOwner, $doctor];
    }

    public function testClinicChartsDefaultToCurrentJalaliPeriod(): void
    {
        [$owner] = $this->clinicWithDoctor();
        [$year, $month] = $this->currentJalali();

        $res = $this->authJson('GET', '/api/v1/dashboard/clinic', $owner);
        self::assertSame(200, $this->responseCode());

        self::assertSame(
            ['patients_year' => $year, 'patients_month' => $month, 'revenue_year' => $year],
            $res['data']['charts_period']
        );
        self::assertCount($this->jalaliMonthLength($year, $month), $res['data']['charts']['appointments_by_day']);
        self::assertCount(12, $res['data']['charts']['revenue_by_month']);
    }

    public function testClinicChartsHonourRequestedPeriod(): void
    {
        [$owner] = $this->clinicWithDoctor();

        // اسفند ۱۴۰۳ سال کبیسه است → ۳۰ روز
        $res = $this->authJson('GET', '/api/v1/dashboard/clinic?patients_year=1403&patients_month=12&revenue_year=1402', $owner);
        self::assertSame(200, $this->responseCode());

        self::assertSame(
            ['patients_year' => 1403, 'patients_month' => 12, 'revenue_year' => 1402],
            $res['data']['charts_period']
        );
        self::assertCount(30, $res['data']['charts']['appointments_by_day']);
    }

    public function testTodayAppointmentIsCountedOnItsJalaliDay(): void
    {
        [$owner, $doctor] = $this->clinicWithDoctor();
        $patient = $this->createUser(['ROLE_USER']);

        $start = time();
        $this->em->persist($this->newAppointment($doctor, $patient, $start, $start + 1_800));
        $this->em->flush();

        $res  = $this->authJson('GET', '/api/v1/dashboard/clinic', $owner);
        $days = $res['data']['charts']['appointments_by_day'];

        $cal = \IntlCalendar::createInstance(new \DateTimeZone('Asia/Tehran'), 'fa_IR@calendar=persian');
        $todayIndex = $cal->get(\IntlCalendar::FIELD_DAY_OF_MONTH) - 1;

        self::assertGreaterThanOrEqual(1, $days[$todayIndex]['count'], 'today\'s slot must land on today\'s bar');
    }

    public function testOutOfRangeParamsAreClamped(): void
    {
        [$owner] = $this->clinicWithDoctor();
        [$year] = $this->currentJalali();

        $res = $this->authJson('GET', '/api/v1/dashboard/clinic?patients_month=99&patients_year=9999&revenue_year=0', $owner);
        self::assertSame(200, $this->responseCode());

        $period = $res['data']['charts_period'];
        self::assertSame(12, $period['patients_month']);
        self::assertSame(1500, $period['patients_year']);
        // revenue_year=0 is falsy → falls back to the current Jalali year
        self::assertSame($year, $period['revenue_year']);
    }

    public function testDoctorChartsUseSameJalaliPeriod(): void
    {
        $owner  = $this->createUser(['ROLE_DOCTOR']);
        $doctor = new Doctor($owner, 'حمیدی');
        $this->em->persist($doctor);
        $this->em->flush();

        $res = $this->authJson('GET', '/api/v1/dashboard/doctor?patients_year=1403&patients_month=1', $owner);
        self::assertSame(200, $this->responseCode());

        self::assertSame(1403, $res['data']['charts_period']['patients_year']);
        self::assertCount(31, $res['data']['charts']['appointments_by_day']);
    }
}
