<?php

namespace App\Patient\Service;

use App\Appointment\Entity\Appointment;
use App\Auth\Repository\UserRepository;
use App\ClinicService\Repository\ServiceItemRepository;
use App\Clinic\Repository\ClinicRepository;
use App\Doctor\Repository\DoctorAddressRepository;
use App\Patient\Entity\PatientRecord;
use App\Patient\Entity\PatientSession;
use App\Patient\Entity\SessionService;
use App\Patient\Repository\PatientRecordRepository;
use App\Patient\Repository\PatientSessionRepository;
use App\Patient\Repository\SessionServiceRepository;
use App\Staff\Repository\ClinicStaffRepository;
use App\Subscription\Service\SubscriptionService;

class PatientService
{
    public function __construct(
        private readonly PatientRecordRepository  $recordRepo,
        private readonly PatientSessionRepository $sessionRepo,
        private readonly SessionServiceRepository $sessionServiceRepo,
        private readonly ServiceItemRepository    $serviceItemRepo,
        private readonly ClinicStaffRepository    $staffRepo,
        private readonly UserRepository           $userRepo,
        private readonly SubscriptionService      $subscriptionService,
        private readonly DoctorAddressRepository  $addressRepo,
        private readonly ClinicRepository         $clinicRepo,
    ) {}

    public function calculateFinalPrice(int $visitPrice, float $baseDiscount, float $suppDiscount, array $serviceItems): array
    {
        $afterBase     = $visitPrice * (1 - $baseDiscount / 100);
        $afterSupp     = $afterBase  * (1 - $suppDiscount / 100);
        $servicesTotal = array_sum(array_column($serviceItems, 'price_rials'));

        return [
            'services_total_rials' => (int) $servicesTotal,
            'final_price_rials'    => (int) round($afterSupp) + (int) $servicesTotal,
        ];
    }

    public function autoCreateOnAppointmentConfirm(Appointment $appointment): void
    {
        $doctor = $appointment->getDoctor();

        // پرونده‌ی پزشک
        $this->autoCreateForEntity('doctor', $doctor->getId(), $appointment, $doctor->getId());

        // کلینیک نوبت را تعیین کن: اول از آدرس انتخاب‌شده، وگرنه اگر دکتر فقط عضو یک کلینیک باشد.
        $clinicId = null;
        $addressId = $appointment->getAddressId();
        if ($addressId !== null) {
            $clinicId = $this->addressRepo->find($addressId)?->getClinicId();
        }
        if ($clinicId === null) {
            $clinics = $this->clinicRepo->findByDoctor($doctor);
            if (count($clinics) === 1) {
                $clinicId = $clinics[0]->getId();
            }
        }

        if ($clinicId !== null) {
            $this->autoCreateForEntity('clinic', $clinicId, $appointment, $clinicId);
        }
    }

    private function autoCreateForEntity(string $entityType, int $entityId, Appointment $appointment, int $createdById): void
    {
        if (!$this->subscriptionService->hasFeature($entityType, $entityId, 'patient_records')) {
            return;
        }

        $patient = $appointment->getUser();

        $record = $this->recordRepo->findByEntityAndUser($entityType, $entityId, $patient);
        if ($record === null) {
            $record = new PatientRecord($entityType, $entityId, $patient, 'system', $createdById);
            $this->recordRepo->save($record);
        }

        $session = new PatientSession($record, $appointment);
        $this->sessionRepo->save($session);
    }

    public function createSession(
        PatientRecord $record,
        array $data,
        string $entityType,
        int $entityId
    ): PatientSession {
        $session = new PatientSession($record);

        if (!empty($data['appointment_uuid'])) {
            // appointment را از بیرون resolve می‌کنند و session را ست می‌کنند
        }

        $session->setInsuranceBaseId(isset($data['insurance_base_id']) ? (int) $data['insurance_base_id'] : null);
        $session->setInsuranceSupplementaryId(isset($data['insurance_supplementary_id']) ? (int) $data['insurance_supplementary_id'] : null);
        $session->setVisitPriceRials((int) ($data['visit_price_rials'] ?? 0));
        $session->setBaseInsuranceDiscountPercent((float) ($data['base_insurance_discount_percent'] ?? 0));
        $session->setSupplementaryDiscountPercent((float) ($data['supplementary_discount_percent'] ?? 0));
        $session->setPaymentMethod($data['payment_method'] ?? 'pending');
        $session->setNotes($data['notes'] ?? null);

        // جمع‌آوری service items
        $serviceItemsData = [];
        foreach (($data['services'] ?? []) as $svc) {
            $item = $this->serviceItemRepo->findByUuid($svc['service_item_uuid'] ?? '');
            if ($item !== null) {
                $serviceItemsData[] = ['price_rials' => $item->getPriceRials()];
            }
        }

        $priceCalc = $this->calculateFinalPrice(
            $session->getVisitPriceRials(),
            $session->getBaseInsuranceDiscountPercent(),
            $session->getSupplementaryDiscountPercent(),
            $serviceItemsData
        );

        $session->setServicesTotalRials($priceCalc['services_total_rials']);
        $session->setFinalPriceRials($priceCalc['final_price_rials']);

        $this->sessionRepo->save($session);

        // ثبت session services
        foreach (($data['services'] ?? []) as $svc) {
            $item = $this->serviceItemRepo->findByUuid($svc['service_item_uuid'] ?? '');
            if ($item === null) {
                continue;
            }
            $staff = !empty($svc['staff_uuid']) ? $this->staffRepo->findByUuid($svc['staff_uuid']) : null;
            $ss    = new SessionService($session, $item, $staff);
            $this->sessionServiceRepo->save($ss);
        }

        return $session;
    }
}
