<?php

namespace Modules\VetAdmission\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Carbon\Carbon;
use Modules\VetAdmission\Entities\VaAdmission;
use Modules\VetAdmission\Entities\VaAdmissionMedication;
use Modules\VetAdmission\Entities\VaMedicationAdministration;
use Modules\VetAdmission\Entities\VaAdmissionVital;
use Modules\VetClinic\Entities\VcMedicine;

/**
 * Order + administer medications for an admission. Doses are computed using
 * the latest known weight (admission vitals -> pet record fallback). When a
 * concentration is supplied, volume_per_dose_ml is derived and stored as a
 * snapshot so the audit trail stays meaningful even if the medicine
 * concentration is later updated.
 */
class VaMedicationController extends Controller
{
    private function biz() { return request()->session()->get('user.business_id'); }

    private function canLog() {
        return auth()->user()->can('vet_admission.log_care')
            || auth()->user()->can('vet_admission.manage_admissions');
    }

    /** List active+inactive med orders for an admission. */
    public function index(Request $request, $admissionId)
    {
        if (!$this->canLog()) abort(403);
        $admission = VaAdmission::forBusiness($this->biz())->findOrFail($admissionId);

        $meds = VaAdmissionMedication::with(['medicine:id,name,unit', 'administrations'])
            ->where('admission_id', $admission->id)
            ->orderByDesc('active')->orderByDesc('id')->get();

        return response()->json(['data' => $meds]);
    }

    /** Latest weight known for the pet (vitals -> pet record). */
    public function currentWeight(Request $request, $admissionId)
    {
        if (!$this->canLog()) abort(403);
        $admission = VaAdmission::with('pet')->forBusiness($this->biz())->findOrFail($admissionId);

        $latestVital = VaAdmissionVital::where('admission_id', $admission->id)
            ->whereNotNull('weight_kg')
            ->orderByDesc('recorded_at')->first(['weight_kg', 'recorded_at']);

        $weight = $latestVital->weight_kg ?? optional($admission->pet)->weight_kg;
        return response()->json([
            'weight_kg' => $weight,
            'source'    => $latestVital ? 'admission_vital' : ($weight ? 'pet_record' : 'unknown'),
            'recorded_at' => $latestVital->recorded_at ?? null,
        ]);
    }

    public function store(Request $request, $admissionId)
    {
        if (!auth()->user()->can('vet_admission.manage_admissions')) abort(403);

        $request->validate([
            'medicine_name'   => 'required|string|max:150',
            'medicine_id'     => 'nullable|integer',
            'route'           => 'required|in:PO,IV,SC,IM,topical,inhalation,PR,other',
            'frequency_hours' => 'required|integer|min:1|max:48',
            'start_at'        => 'required|date',
            'duration_hours'  => 'nullable|integer|min:1|max:1440',
            'dose_mg_per_kg'  => 'nullable|numeric|gt:0',
            'dose_total_mg'   => 'nullable|numeric|gt:0',
            'concentration_mg_per_ml' => 'nullable|numeric|gt:0',
            'weight_kg_used'  => 'nullable|numeric|gt:0',
            'notes'           => 'nullable|string|max:500',
        ]);

        $admission = VaAdmission::forBusiness($this->biz())->findOrFail($admissionId);

        // Compute volume per dose when both total-mg and concentration are known.
        $totalMg = $request->dose_total_mg;
        if (!$totalMg && $request->dose_mg_per_kg && $request->weight_kg_used) {
            $totalMg = (float) $request->dose_mg_per_kg * (float) $request->weight_kg_used;
        }
        $volumeMl = null;
        if ($totalMg && $request->concentration_mg_per_ml) {
            $volumeMl = round($totalMg / (float) $request->concentration_mg_per_ml, 4);
        }

        $startAt = Carbon::parse($request->start_at);
        $endAt = $request->duration_hours
            ? $startAt->copy()->addHours((int) $request->duration_hours)
            : null;

        $med = VaAdmissionMedication::create([
            'admission_id'      => $admission->id,
            'medicine_id'       => $request->medicine_id ?: null,
            'medicine_name'     => $request->medicine_name,
            'route'             => $request->route,
            'dose_mg_per_kg'    => $request->dose_mg_per_kg,
            'dose_total_mg'     => $totalMg,
            'concentration_mg_per_ml' => $request->concentration_mg_per_ml,
            'volume_per_dose_ml' => $volumeMl,
            'weight_kg_used'    => $request->weight_kg_used,
            'frequency_hours'   => (int) $request->frequency_hours,
            'duration_hours'    => $request->duration_hours,
            'start_at'          => $startAt,
            'end_at'            => $endAt,
            'notes'             => $request->notes,
            'active'            => true,
            'created_by'        => auth()->id(),
        ]);

        $this->seedAdministrations($med);

        return response()->json(['success' => true, 'msg' => 'Medication order created.', 'medication_id' => $med->id]);
    }

    public function stop(Request $request, $id)
    {
        if (!auth()->user()->can('vet_admission.manage_admissions')) abort(403);

        $med = VaAdmissionMedication::findOrFail($id);
        $admission = VaAdmission::forBusiness($this->biz())->findOrFail($med->admission_id);

        $med->update(['active' => false, 'end_at' => $med->end_at ?: now()]);
        // Cancel future-pending administrations
        VaMedicationAdministration::where('admission_medication_id', $med->id)
            ->where('status', 'pending')
            ->where('due_at', '>', now())
            ->update(['status' => 'rescheduled', 'notes' => 'Order stopped']);

        return response()->json(['success' => true, 'msg' => 'Medication stopped.']);
    }

    /** Mark a single dose given/missed/refused (one click from the flowsheet). */
    public function administer(Request $request, $administrationId)
    {
        if (!$this->canLog()) abort(403);

        $request->validate([
            'status' => 'required|in:given,missed,refused',
            'actual_volume_ml' => 'nullable|numeric|gte:0',
            'actual_dose_mg'   => 'nullable|numeric|gte:0',
            'notes' => 'nullable|string|max:500',
        ]);

        $row = VaMedicationAdministration::findOrFail($administrationId);

        $row->update([
            'administered_at' => now(),
            'given_by'        => auth()->id(),
            'status'          => $request->status,
            'actual_volume_ml' => $request->actual_volume_ml,
            'actual_dose_mg'   => $request->actual_dose_mg,
            'notes'            => $request->notes,
        ]);

        return response()->json(['success' => true, 'status' => $row->status]);
    }

    /** Generate the expected administration rows for a fresh order. */
    private function seedAdministrations(VaAdmissionMedication $med): void
    {
        $start = $med->start_at->copy();
        $end   = $med->end_at ?: $med->start_at->copy()->addDays(7);  // cap for open-ended
        $step  = max(1, (int) $med->frequency_hours);

        $cursor = $start->copy();
        while ($cursor->lt($end)) {
            VaMedicationAdministration::create([
                'admission_medication_id' => $med->id,
                'due_at'                  => $cursor->copy(),
                'status'                  => 'pending',
            ]);
            $cursor->addHours($step);
        }
    }
}
