<?php

namespace App\Tests\Appointment;

use App\Appointment\Entity\Appointment;
use App\Appointment\Repository\AppointmentRepository;
use App\Doctor\Entity\Doctor;
use App\Tests\ApiTestCase;

/**
 * Filtered + paginated doctor appointment list backing the dashboard filter bar
 * (AppointmentRepository::searchByDoctor).
 */
class DoctorAppointmentFilterTest extends ApiTestCase
{
    private function repo(): AppointmentRepository
    {
        return $this->em->getRepository(Appointment::class);
    }

    private function makeDoctor(): Doctor
    {
        $doctor = new Doctor($this->createUser(['ROLE_DOCTOR']), 'دکتر تست');
        $this->em->persist($doctor);
        $this->em->flush();

        return $doctor;
    }

    private function booking(Doctor $doctor, int $start, ?string $status = null, ?string $name = null): Appointment
    {
        $a = $this->newAppointment($doctor, $this->createUser(), $start, $start + 1_800);
        if ($name !== null) {
            $a->setPatientName($name);
        }
        if ($status === Appointment::STATUS_COMPLETED) {
            $a->transitionTo(Appointment::STATUS_CONFIRMED);
            $a->transitionTo(Appointment::STATUS_COMPLETED);
        } elseif ($status !== null) {
            $a->transitionTo($status);
        }
        $this->em->persist($a);
        $this->em->flush();

        return $a;
    }

    public function testStatusFilterExcludesVisited(): void
    {
        $doctor = $this->makeDoctor();
        $base   = time() + 86_400;
        $this->booking($doctor, $base);                                        // pending
        $this->booking($doctor, $base + 3_600, Appointment::STATUS_CONFIRMED);
        $this->booking($doctor, $base + 7_200, Appointment::STATUS_COMPLETED);

        $res = $this->repo()->searchByDoctor(
            $doctor,
            [Appointment::STATUS_PENDING, Appointment::STATUS_CONFIRMED],
        );

        self::assertSame(2, $res['total']);
        foreach ($res['items'] as $a) {
            self::assertNotSame(Appointment::STATUS_COMPLETED, $a->getStatus());
        }
    }

    public function testDateRangeAndNameSearch(): void
    {
        $doctor = $this->makeDoctor();
        $base   = time() + 86_400;
        $this->booking($doctor, $base, null, 'علی رضایی');
        $this->booking($doctor, $base + 200_000, null, 'مریم کاظمی');

        $inRange = $this->repo()->searchByDoctor($doctor, [], null, $base - 60, $base + 60);
        self::assertSame(1, $inRange['total']);
        self::assertSame('علی رضایی', $inRange['items'][0]->getPatientName());

        $byName = $this->repo()->searchByDoctor($doctor, [], null, null, null, 'کاظمی');
        self::assertSame(1, $byName['total']);
        self::assertSame('مریم کاظمی', $byName['items'][0]->getPatientName());
    }

    public function testPaginationSlicesAndReportsFullTotal(): void
    {
        $doctor = $this->makeDoctor();
        $base   = time() + 86_400;
        for ($i = 0; $i < 5; $i++) {
            $this->booking($doctor, $base + $i * 3_600);
        }

        $page2 = $this->repo()->searchByDoctor($doctor, [], null, null, null, null, null, 2, 2);

        self::assertSame(5, $page2['total'], 'total باید کل نتایج باشد نه اندازهٔ صفحه');
        self::assertCount(2, $page2['items']);
    }

    public function testEmptyResultForUnmatchedFilter(): void
    {
        $doctor = $this->makeDoctor();
        $this->booking($doctor, time() + 86_400);

        $res = $this->repo()->searchByDoctor($doctor, [Appointment::STATUS_NO_SHOW]);

        self::assertSame(0, $res['total']);
        self::assertSame([], $res['items']);
    }
}
