<?php

namespace Modules\ClinicCore\Entities\Services;

use Modules\ClinicCore\Entities\ClcMedicine;
use Modules\ClinicCore\Entities\ClcVaccination;
use Modules\ClinicCore\Entities\ClcVaccineType;
use Carbon\Carbon;

class VaccinationService
{
    /**
     * SIFA P4-T2 — inventory consumption bridge for administered vaccinations.
     *
     * When a vaccination is administered ('administered' status, taken at the
     * clinic) with a medicine_id whose medicine carries an ERP product_id, decrement
     * ONE dose from stock via a proper ERP stock adjustment. This event never
     * reaches billing on its own, so the consumption bridge is the correct path
     * (a billed vaccine, by contrast, would ride MedBilling's sell — do not
     * double-count). Idempotent via clc_vaccinations.consumed_adjustment_id.
     *
     * Fail-soft: any resolution failure leaves the vaccination untouched.
     */
    public function consumeDoseIfApplicable(ClcVaccination $vax): void
    {
        try {
            if (!\Schema::hasColumn('clc_vaccinations', 'consumed_adjustment_id')) {
                return;
            }
            // Only administered-at-clinic doses consume in-house stock; already-
            // consumed rows are skipped (idempotent).
            if ($vax->status !== 'administered' || $vax->taken_status !== 'taken_in') {
                return;
            }
            if (!empty($vax->consumed_adjustment_id) || empty($vax->medicine_id)) {
                return;
            }

            $medicine = ClcMedicine::where('business_id', $vax->business_id)->find($vax->medicine_id);
            if (!$medicine || empty($medicine->product_id)) {
                return;
            }

            $locationId = $this->resolveLocationId($vax);
            if (!$locationId) {
                return;
            }

            $adjustmentId = app(ClinicalConsumptionService::class)->consume(
                (int) $vax->business_id,
                (int) $locationId,
                (int) $medicine->product_id,
                1.0,
                'vaccination',
                ['vaccination_id' => $vax->id]
            );

            if ($adjustmentId) {
                $vax->forceFill(['consumed_adjustment_id' => $adjustmentId])->saveQuietly();
            }
        } catch (\Throwable $e) {
            \Log::warning('VaccinationService consumeDoseIfApplicable skipped: ' . $e->getMessage());
        }
    }

    /**
     * Resolve the ERP location for the dose: the appointment's location if set,
     * else the business's default (first) location.
     */
    protected function resolveLocationId(ClcVaccination $vax): ?int
    {
        try {
            if ($vax->appointment_id) {
                $loc = \DB::table('clc_appointments')->where('id', $vax->appointment_id)->value('location_id');
                if ($loc) {
                    // clc_appointments.location_id points at clc_clinic_locations; map to the
                    // ERP business_location_id when present, else fall through to default.
                    $bl = \DB::table('clc_clinic_locations')->where('id', $loc)->value('business_location_id');
                    if ($bl) return (int) $bl;
                }
            }
        } catch (\Throwable $e) {
            // fall through to default
        }

        $default = \DB::table('business_locations')
            ->where('business_id', $vax->business_id)
            ->orderBy('id')
            ->value('id');
        return $default ? (int) $default : null;
    }

    public function calculateNextDue(string $administeredDate, int $validForMonths): string
    {
        return Carbon::parse($administeredDate)->addMonths($validForMonths)->toDateString();
    }

    public function getOverdueCount(int $businessId): int
    {
        return ClcVaccination::where('business_id', $businessId)
            ->where('status', 'administered')
            ->where('next_due_date', '<', Carbon::today())
            ->count();
    }

    public function getDueSoon(int $businessId, int $withinDays = 30): \Illuminate\Database\Eloquent\Collection
    {
        $today = Carbon::today();
        return ClcVaccination::with(['pet', 'vaccineType', 'owner'])
            ->where('business_id', $businessId)
            ->where('status', 'administered')
            ->whereBetween('next_due_date', [$today, $today->copy()->addDays($withinDays)])
            ->orderBy('next_due_date')
            ->get();
    }

    public function markOverdue(int $businessId): int
    {
        return ClcVaccination::where('business_id', $businessId)
            ->where('status', 'administered')
            ->where('next_due_date', '<', Carbon::today())
            ->update(['status' => 'overdue']);
    }
}
