<?php

namespace Modules\VetAdmission\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\DB;
use Carbon\Carbon;
use Modules\VetAdmission\Entities\VaAdmission;
use Modules\VetAdmission\Entities\VaAdmissionCarePlan;
use Modules\VetAdmission\Entities\VaAdmissionFluid;
use Modules\VetAdmission\Entities\VaAdmissionMedication;
use Modules\VetAdmission\Entities\VaCareTaskType;
use Modules\VetAdmission\Entities\VaMedicationAdministration;
use Modules\VetAdmission\Entities\VaProtocol;

/**
 * Treatment protocols — list, manage, and apply to admissions. Apply
 * expands the protocol's items into the corresponding tables in a single
 * transaction and records the expansion in va_protocol_applications so the
 * apply event is auditable + reversible.
 */
class VaProtocolController extends Controller
{
    private function biz() { return request()->session()->get('user.business_id'); }

    public function index(Request $request)
    {
        if (!auth()->user()->can('vet_admission.manage_admissions')
            && !auth()->user()->can('vet_admission.manage_settings')) abort(403);

        $businessId = (int) $this->biz();

        // System protocols (read-only here — clone to customise).
        $systemProtocols = VaProtocol::with('items')
            ->whereNull('business_id')
            ->where('status', 'active')
            ->orderBy('name')->get();

        // Business-owned protocols (full CRUD).
        $ownProtocols = VaProtocol::with('items')
            ->where('business_id', $businessId)
            ->orderBy('name')->get();

        return view('vetAdmission::protocols.index', compact('systemProtocols', 'ownProtocols'));
    }

    /** Create a new business-owned protocol. */
    public function store(Request $request)
    {
        if (!auth()->user()->can('vet_admission.manage_admissions')) abort(403);
        $request->validate([
            'name'        => 'required|string|max:120',
            'species'     => 'nullable|in:canine,feline,exotic,other',
            'description' => 'nullable|string|max:2000',
        ]);

        $p = VaProtocol::create([
            'business_id' => (int) $this->biz(),
            'name'        => $request->name,
            'species'     => $request->species,
            'description' => $request->description,
            'status'      => 'active',
        ]);
        return response()->json(['success' => true, 'id' => $p->id]);
    }

    /** Update name / species / description on a business-owned protocol. */
    public function update(Request $request, $id)
    {
        if (!auth()->user()->can('vet_admission.manage_admissions')) abort(403);
        $p = VaProtocol::where('business_id', $this->biz())->findOrFail($id);
        $request->validate([
            'name'        => 'required|string|max:120',
            'species'     => 'nullable|in:canine,feline,exotic,other',
            'description' => 'nullable|string|max:2000',
            'status'      => 'nullable|in:active,inactive',
        ]);
        $p->update($request->only(['name', 'species', 'description', 'status']));
        return response()->json(['success' => true]);
    }

    /** Soft delete (status=inactive) — keeps applied history intact. */
    public function destroy(Request $request, $id)
    {
        if (!auth()->user()->can('vet_admission.manage_admissions')) abort(403);
        $p = VaProtocol::where('business_id', $this->biz())->findOrFail($id);
        $p->update(['status' => 'inactive']);
        return response()->json(['success' => true]);
    }

    /**
     * Clone any visible protocol (system or your own) into a fresh business-
     * owned copy you can then edit freely.
     */
    public function clone(Request $request, $id)
    {
        if (!auth()->user()->can('vet_admission.manage_admissions')) abort(403);

        $businessId = (int) $this->biz();
        $src = VaProtocol::forBusiness($businessId)->with('items')->findOrFail($id);

        $copy = VaProtocol::create([
            'business_id' => $businessId,
            'name'        => $src->name . ' (copy)',
            'species'     => $src->species,
            'description' => $src->description,
            'status'      => 'active',
        ]);
        foreach ($src->items as $it) {
            $copy->items()->create([
                'kind'              => $it->kind,
                'care_task_type_id' => $it->care_task_type_id,
                'medicine_id'       => $it->medicine_id,
                'label'             => $it->label,
                'payload'           => $it->payload,
                'sort_order'        => $it->sort_order,
            ]);
        }
        return response()->json(['success' => true, 'id' => $copy->id, 'msg' => 'Protocol cloned — edit it under "Your protocols".']);
    }

    /** Append an item to a business-owned protocol. */
    public function addItem(Request $request, $protocolId)
    {
        if (!auth()->user()->can('vet_admission.manage_admissions')) abort(403);
        $p = VaProtocol::where('business_id', $this->biz())->findOrFail($protocolId);

        $request->validate([
            'kind'    => 'required|in:care_task,medication,fluid',
            'label'   => 'required|string|max:150',
            'payload' => 'nullable|array',
        ]);
        $it = $p->items()->create([
            'kind'       => $request->kind,
            'label'      => $request->label,
            'payload'    => $request->payload ?: [],
            'sort_order' => ($p->items()->max('sort_order') ?? 0) + 1,
        ]);
        return response()->json(['success' => true, 'id' => $it->id]);
    }

    /** Remove an item from a business-owned protocol. */
    public function deleteItem(Request $request, $itemId)
    {
        if (!auth()->user()->can('vet_admission.manage_admissions')) abort(403);
        $it = \Modules\VetAdmission\Entities\VaProtocolItem::findOrFail($itemId);
        $owner = VaProtocol::where('business_id', $this->biz())->find($it->protocol_id);
        if (!$owner) abort(403, 'Cannot edit a system protocol — clone it first.');
        $it->delete();
        return response()->json(['success' => true]);
    }

    /** AJAX: protocols for the species of the admission's pet (with a fallback to nullable-species). */
    public function forAdmission(Request $request, $admissionId)
    {
        if (!auth()->user()->can('vet_admission.manage_admissions')) abort(403);

        $admission = VaAdmission::with('pet')->forBusiness((int) $this->biz())->findOrFail($admissionId);
        $species = strtolower(optional($admission->pet)->species ?? '');

        $protocols = VaProtocol::with('items')
            ->forBusiness((int) $this->biz())
            ->where('status', 'active')
            ->where(function ($q) use ($species) {
                $q->whereNull('species');
                if ($species) $q->orWhere('species', $species);
            })
            ->orderBy('name')->get();

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

    /** Apply a protocol to an admission. */
    public function apply(Request $request, $admissionId)
    {
        if (!auth()->user()->can('vet_admission.manage_admissions')) abort(403);
        $request->validate(['protocol_id' => 'required|integer']);

        $admission = VaAdmission::with('pet')->forBusiness((int) $this->biz())->findOrFail($admissionId);
        $protocol  = VaProtocol::with('items')->forBusiness((int) $this->biz())->findOrFail($request->protocol_id);

        // Pull latest known weight for dose computation.
        $weight = optional($admission->pet)->weight_kg
            ?? optional(\Modules\VetAdmission\Entities\VaAdmissionVital::where('admission_id', $admission->id)
                ->whereNotNull('weight_kg')->orderByDesc('recorded_at')->first())->weight_kg;

        return DB::transaction(function () use ($admission, $protocol, $weight) {
            $expanded = ['care_plans' => [], 'medications' => [], 'fluids' => []];
            $start = Carbon::now();

            foreach ($protocol->items as $item) {
                $p = $item->payload ?: [];

                if ($item->kind === 'care_task') {
                    $taskType = $this->resolveCareTaskType((int) $this->biz(), $p['task_name'] ?? $item->label);
                    if (!$taskType) continue;
                    $row = VaAdmissionCarePlan::create([
                        'admission_id'      => $admission->id,
                        'care_task_type_id' => $taskType->id,
                        'times_per_day'     => (int) ($p['times_per_day'] ?? 1),
                        'schedule_times'    => $p['schedule_times'] ?? null,
                        'instructions'      => $item->label,
                        'active'            => true,
                    ]);
                    $expanded['care_plans'][] = $row->id;

                } elseif ($item->kind === 'medication') {
                    $totalMg = ($p['dose_mg_per_kg'] ?? null) && $weight
                        ? (float) $p['dose_mg_per_kg'] * (float) $weight
                        : ($p['dose_total_mg'] ?? null);
                    $volumeMl = ($totalMg && ($p['concentration_mg_per_ml'] ?? null))
                        ? round((float) $totalMg / (float) $p['concentration_mg_per_ml'], 4)
                        : null;

                    $freqHours = (int) ($p['frequency_hours'] ?? 8);
                    $durHours  = $p['duration_hours'] ?? null;
                    $startAt   = $start->copy();
                    $endAt     = $durHours ? $startAt->copy()->addHours((int) $durHours) : null;

                    $med = VaAdmissionMedication::create([
                        'admission_id'            => $admission->id,
                        'medicine_id'             => $p['medicine_id'] ?? null,
                        'medicine_name'           => $p['medicine_name'] ?? $item->label,
                        'route'                   => $p['route'] ?? 'PO',
                        'dose_mg_per_kg'          => $p['dose_mg_per_kg'] ?? null,
                        'dose_total_mg'           => $totalMg,
                        'concentration_mg_per_ml' => $p['concentration_mg_per_ml'] ?? null,
                        'volume_per_dose_ml'      => $volumeMl,
                        'weight_kg_used'          => $weight,
                        'frequency_hours'         => $freqHours,
                        'duration_hours'          => $durHours,
                        'start_at'                => $startAt,
                        'end_at'                  => $endAt,
                        'notes'                   => 'Auto-applied from protocol: ' . $protocol->name,
                        'active'                  => true,
                        'created_by'              => auth()->id(),
                    ]);
                    $expanded['medications'][] = $med->id;

                    // Seed dose administrations.
                    $cursor = $startAt->copy();
                    $cap = $endAt ?: $startAt->copy()->addDays(7);
                    while ($cursor->lt($cap)) {
                        VaMedicationAdministration::create([
                            'admission_medication_id' => $med->id,
                            'due_at'                  => $cursor->copy(),
                            'status'                  => 'pending',
                        ]);
                        $cursor->addHours($freqHours);
                    }

                } elseif ($item->kind === 'fluid') {
                    $rate = (float) ($p['rate_ml_per_hr'] ?? 0);
                    $bag  = (float) ($p['bag_size_ml'] ?? 0);
                    $hoursRun = $rate > 0 ? $bag / $rate : 0;
                    $row = VaAdmissionFluid::create([
                        'admission_id'          => $admission->id,
                        'fluid_type'            => $p['fluid_type'] ?? $item->label,
                        'rate_ml_per_hr'        => $rate,
                        'rate_ml_per_kg_per_hr' => $p['rate_ml_per_kg_per_hr'] ?? null,
                        'bag_size_ml'           => $bag,
                        'started_at'            => $start->copy(),
                        'estimated_end_at'      => $hoursRun > 0 ? $start->copy()->addMinutes((int) round($hoursRun * 60)) : null,
                        'notes'                 => 'Auto-applied from protocol: ' . $protocol->name,
                        'active'                => true,
                        'created_by'            => auth()->id(),
                    ]);
                    $expanded['fluids'][] = $row->id;
                }
            }

            \DB::table('va_protocol_applications')->insert([
                'admission_id' => $admission->id,
                'protocol_id'  => $protocol->id,
                'expanded_ids' => json_encode($expanded),
                'applied_by'   => auth()->id(),
                'applied_at'   => now(),
                'created_at'   => now(),
                'updated_at'   => now(),
            ]);

            return response()->json([
                'success'  => true,
                'msg'      => "Applied '{$protocol->name}' — "
                    . count($expanded['care_plans'])  . ' care, '
                    . count($expanded['medications']) . ' meds, '
                    . count($expanded['fluids'])      . ' fluid(s).',
                'expanded' => $expanded,
            ]);
        });
    }

    /** Resolve a care-task type by name, falling back to system defaults (business_id NULL). */
    private function resolveCareTaskType(int $businessId, ?string $name): ?VaCareTaskType
    {
        if (!$name) return null;
        return VaCareTaskType::where('name', $name)
            ->where(function ($q) use ($businessId) {
                $q->where('business_id', $businessId)->orWhereNull('business_id');
            })
            ->orderByRaw('CASE WHEN business_id IS NULL THEN 1 ELSE 0 END')
            ->first();
    }
}
