<?php

namespace Modules\VetAdmission\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Carbon\Carbon;
use Modules\VetAdmission\Entities\Services\CarePlanSlotService;
use Modules\VetAdmission\Entities\VaAdmission;
use Modules\VetAdmission\Entities\VaAdmissionCarePlan;
use Modules\VetAdmission\Entities\VaCareLog;
use Modules\VetAdmission\Entities\VaCareTaskType;
use Modules\VetAdmission\Entities\VaAdmissionVital;
use Modules\VetAdmission\Entities\VaWard;
use Modules\VetClinic\Entities\VcPet;
use Modules\VetClinic\Entities\VcDoctor;
use App\Contact;
use Yajra\DataTables\Facades\DataTables;

class VaAdmissionController extends Controller
{
    private function biz()
    {
        return request()->session()->get('user.business_id');
    }

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

    // ── List ────────────────────────────────────────────────────────────────

    public function index()
    {
        if (!$this->canView()) abort(403, 'Unauthorized action.');

        $businessId = $this->biz();
        $stats = [
            'admitted'   => VaAdmission::forBusiness($businessId)->where('status', 'admitted')->count(),
            'discharged' => VaAdmission::forBusiness($businessId)->where('status', 'discharged')->count(),
            'total'      => VaAdmission::forBusiness($businessId)->count(),
            'wards'      => VaWard::forBusiness($businessId)->active()->count(),
        ];
        $wards = VaWard::forBusiness($businessId)->active()->orderBy('name')->get();

        return view('vetAdmission::admissions.index', compact('stats', 'wards'));
    }

    public function list(Request $request)
    {
        if (!$this->canView()) abort(403, 'Unauthorized action.');

        $query = VaAdmission::with(['pet', 'owner', 'ward', 'attendingDoctor'])
            ->forBusiness($this->biz());

        if ($request->filled('status'))  $query->where('status', $request->status);
        if ($request->filled('ward_id')) $query->where('ward_id', $request->ward_id);
        if ($request->filled('type'))    $query->where('type', $request->type);

        return DataTables::of($query->orderByDesc('admitted_at'))
            ->addColumn('admission_no_col', function ($row) {
                return '<a href="' . route('va.admissions.show', $row->id) . '" style="font-weight:700;">'
                    . e($row->admission_no) . '</a>';
            })
            ->addColumn('pet_col', function ($row) {
                $pet = optional($row->pet)->petname ?? '—';
                $owner = optional($row->owner)->name ?? '';
                return '<strong>' . e($pet) . '</strong>'
                    . ($owner ? '<br><small class="text-muted">' . e($owner) . '</small>' : '');
            })
            ->addColumn('ward_col', fn($row) => e(optional($row->ward)->name ?? '—'))
            ->addColumn('type_badge', fn($row) => '<span class="label label-default">'
                . ucfirst(str_replace('_', ' ', $row->type)) . '</span>')
            ->addColumn('admitted_col', fn($row) => optional($row->admitted_at)->format('d M Y H:i') ?? '—')
            ->addColumn('stay_col', fn($row) => $row->stay_days . 'd')
            ->addColumn('status_badge', function ($row) {
                $map = ['admitted' => 'warning', 'discharged' => 'success', 'transferred' => 'info', 'deceased' => 'default'];
                return '<span class="label label-' . ($map[$row->status] ?? 'default') . '">'
                    . ucfirst($row->status) . '</span>';
            })
            ->addColumn('action', function ($row) {
                return '<a href="' . route('va.admissions.show', $row->id) . '" class="btn btn-xs btn-info">'
                    . '<i class="fa fa-eye"></i></a>';
            })
            ->rawColumns(['admission_no_col', 'pet_col', 'type_badge', 'status_badge', 'action'])
            ->make(true);
    }

    // ── Create / Store ───────────────────────────────────────────────────────

    public function create()
    {
        if (!auth()->user()->can('vet_admission.manage_admissions')) abort(403, 'Unauthorized action.');

        $businessId = $this->biz();
        $wards      = VaWard::forBusiness($businessId)->active()->orderBy('name')->get();
        $doctors    = VcDoctor::where('business_id', $businessId)->where('status', 'active')->orderBy('name')->get();
        $taskTypes  = VaCareTaskType::forBusiness($businessId)->active()->orderBy('sort_order')->orderBy('name')->get();

        $preselectedPet = null;
        if (request('pet_id')) {
            $preselectedPet = VcPet::where('business_id', $businessId)->find(request('pet_id'));
        }

        return view('vetAdmission::admissions.create', compact('wards', 'doctors', 'taskTypes', 'preselectedPet'));
    }

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

        $request->validate([
            'pet_id'      => 'required|integer',
            'contact_id'  => 'required|integer',
            'type'        => 'required|in:hospitalization,boarding,surgery_recovery,observation,isolation',
            'admitted_at' => 'required|date',
        ]);

        $businessId = $this->biz();

        // Human-readable, per-business sequential number (business segment keeps
        // it globally unique against the admission_no unique index).
        $seq = VaAdmission::where('business_id', $businessId)->count() + 1;
        $admissionNo = 'ADM-' . $businessId . '-' . str_pad($seq, 5, '0', STR_PAD_LEFT);
        while (VaAdmission::where('admission_no', $admissionNo)->exists()) {
            $admissionNo = 'ADM-' . $businessId . '-' . str_pad(++$seq, 5, '0', STR_PAD_LEFT);
        }

        $admission = VaAdmission::create([
            'business_id'           => $businessId,
            'admission_no'          => $admissionNo,
            'pet_id'                => $request->pet_id,
            'contact_id'            => $request->contact_id,
            'appointment_id'        => $request->appointment_id ?: null,
            'ward_id'               => $request->ward_id ?: null,
            'type'                  => $request->type,
            'reason'                => $request->reason,
            'diagnosis'             => $request->diagnosis,
            'admitting_doctor_id'   => $request->admitting_doctor_id ?: null,
            'attending_doctor_id'   => $request->attending_doctor_id ?: null,
            'admitted_at'           => $request->admitted_at,
            'expected_discharge_at' => $request->expected_discharge_at ?: null,
            'status'                => 'admitted',
            'deposit_amount'        => $request->deposit_amount ?: null,
            'daily_rate'            => $request->daily_rate ?: null,
            'created_by'            => auth()->id(),
        ]);

        // Initial care plan rows
        $taskIds  = (array) $request->input('care_task_type_id', []);
        $times    = (array) $request->input('times_per_day', []);
        $instr    = (array) $request->input('care_instructions', []);
        foreach ($taskIds as $i => $taskId) {
            if (empty($taskId)) continue;
            VaAdmissionCarePlan::create([
                'admission_id'      => $admission->id,
                'care_task_type_id' => $taskId,
                'times_per_day'     => max(1, (int) ($times[$i] ?? 1)),
                'instructions'      => $instr[$i] ?? null,
                'active'            => true,
            ]);
        }

        return redirect()->route('va.admissions.show', $admission->id)
            ->with('status', ['success' => 1, 'msg' => __('vetAdmission::lang.admission_created')]);
    }

    // ── Patient chart ────────────────────────────────────────────────────────

    public function show($id)
    {
        if (!$this->canView()) abort(403, 'Unauthorized action.');

        $admission = VaAdmission::with([
            'pet', 'owner', 'ward', 'admittingDoctor', 'attendingDoctor',
            'carePlan' => fn($q) => $q->with('taskType'),
            'vitals.recordedBy',
        ])->forBusiness($this->biz())->findOrFail($id);

        $today    = Carbon::today()->toDateString();
        $todayLogs = VaCareLog::where('admission_id', $admission->id)
            ->whereDate('care_date', $today)->get()
            ->keyBy(fn($l) => $l->care_plan_id . '_' . $l->slot_index);

        // Build today's checklist: N slots per active care-plan item
        $checklist = [];
        foreach ($admission->carePlan->where('active', true) as $cp) {
            $slots = [];
            for ($i = 0; $i < max(1, (int) $cp->times_per_day); $i++) {
                $log = $todayLogs->get($cp->id . '_' . $i);
                $slots[] = [
                    'index'  => $i,
                    'time'   => is_array($cp->schedule_times) ? ($cp->schedule_times[$i] ?? null) : null,
                    'status' => $log ? $log->status : 'pending',
                    'log'    => $log,
                ];
            }
            $checklist[] = ['plan' => $cp, 'slots' => $slots];
        }

        // Care history (last 7 days, excluding today)
        $history = VaCareLog::with(['taskType', 'doneBy'])
            ->where('admission_id', $admission->id)
            ->whereDate('care_date', '<', $today)
            ->orderByDesc('care_date')->orderByDesc('done_at')
            ->limit(60)->get()
            ->groupBy(fn($l) => optional($l->care_date)->format('Y-m-d'));

        $taskTypes = VaCareTaskType::forBusiness($this->biz())->active()
            ->orderBy('sort_order')->orderBy('name')->get();

        return view('vetAdmission::admissions.show', compact('admission', 'checklist', 'history', 'taskTypes', 'today'));
    }

    // ── Edit / Update ────────────────────────────────────────────────────────

    public function edit($id)
    {
        if (!auth()->user()->can('vet_admission.manage_admissions')) abort(403, 'Unauthorized action.');

        $businessId = $this->biz();
        $admission  = VaAdmission::with('pet')->forBusiness($businessId)->findOrFail($id);
        $wards      = VaWard::forBusiness($businessId)->active()->orderBy('name')->get();
        $doctors    = VcDoctor::where('business_id', $businessId)->where('status', 'active')->orderBy('name')->get();
        $taskTypes  = VaCareTaskType::forBusiness($businessId)->active()->orderBy('sort_order')->orderBy('name')->get();

        return view('vetAdmission::admissions.create', compact('admission', 'wards', 'doctors', 'taskTypes'));
    }

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

        $request->validate([
            'type'        => 'required|in:hospitalization,boarding,surgery_recovery,observation,isolation',
            'admitted_at' => 'required|date',
        ]);

        $admission = VaAdmission::forBusiness($this->biz())->findOrFail($id);
        $admission->update([
            'ward_id'               => $request->ward_id ?: null,
            'type'                  => $request->type,
            'reason'                => $request->reason,
            'diagnosis'             => $request->diagnosis,
            'admitting_doctor_id'   => $request->admitting_doctor_id ?: null,
            'attending_doctor_id'   => $request->attending_doctor_id ?: null,
            'admitted_at'           => $request->admitted_at,
            'expected_discharge_at' => $request->expected_discharge_at ?: null,
            'deposit_amount'        => $request->deposit_amount ?: null,
            'daily_rate'            => $request->daily_rate ?: null,
        ]);

        return redirect()->route('va.admissions.show', $admission->id)
            ->with('status', ['success' => 1, 'msg' => __('vetAdmission::lang.updated')]);
    }

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

        $request->validate([
            'status'        => 'required|in:discharged,transferred,deceased',
            'discharged_at' => 'required|date',
        ]);

        $admission = VaAdmission::forBusiness($this->biz())->findOrFail($id);
        if ($admission->status !== 'admitted') {
            return response()->json(['success' => false, 'msg' => __('vetAdmission::lang.already_closed')], 422);
        }

        $admission->update([
            'status'            => $request->status,
            'discharged_at'     => $request->discharged_at,
            'discharge_summary' => $request->discharge_summary,
        ]);

        return response()->json(['success' => true, 'msg' => __('vetAdmission::lang.discharge_done')]);
    }

    // ── Ward occupancy board ─────────────────────────────────────────────────

    public function board()
    {
        if (!$this->canView()) abort(403, 'Unauthorized action.');

        $businessId = $this->biz();
        $wards = VaWard::forBusiness($businessId)->active()
            ->with(['currentAdmissions' => fn($q) => $q->with('pet', 'owner')])
            ->orderBy('name')->get();

        $unassigned = VaAdmission::with('pet', 'owner')
            ->forBusiness($businessId)->where('status', 'admitted')->whereNull('ward_id')->get();

        return view('vetAdmission::admissions.board', compact('wards', 'unassigned'));
    }

    // ── Care plan management ─────────────────────────────────────────────────

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

        $request->validate([
            'care_task_type_id' => 'required|integer',
            'times_per_day'     => 'required|integer|min:1|max:24',
        ]);

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

        VaAdmissionCarePlan::create([
            'admission_id'      => $admission->id,
            'care_task_type_id' => $request->care_task_type_id,
            'times_per_day'     => $request->times_per_day,
            'instructions'      => $request->instructions,
            'active'            => true,
        ]);

        return response()->json(['success' => true, 'msg' => __('vetAdmission::lang.care_task_added')]);
    }

    public function removeCarePlan($planId)
    {
        if (!auth()->user()->can('vet_admission.manage_admissions')) abort(403, 'Unauthorized action.');

        $plan = VaAdmissionCarePlan::whereHas('admission', fn($q) => $q->forBusiness($this->biz()))
            ->findOrFail($planId);
        $plan->delete();

        return response()->json(['success' => true, 'msg' => __('vetAdmission::lang.care_task_removed')]);
    }

    // ── Care log (the routine checklist) ─────────────────────────────────────

    public function toggleCareLog(Request $request, $id)
    {
        if (!auth()->user()->can('vet_admission.log_care')) abort(403, 'Unauthorized action.');

        $request->validate([
            'care_plan_id' => 'required|integer',
            'slot_index'   => 'required|integer|min:0',
            'action'       => 'required|in:done,skipped,undo',
        ]);

        $admission = VaAdmission::forBusiness($this->biz())->findOrFail($id);
        $careDate  = $request->care_date ?: Carbon::today()->toDateString();

        // Validate the care plan belongs to this admission
        $plan = VaAdmissionCarePlan::where('id', $request->care_plan_id)
            ->where('admission_id', $admission->id)->firstOrFail();

        $existing = VaCareLog::where('admission_id', $admission->id)
            ->where('care_plan_id', $plan->id)
            ->whereDate('care_date', $careDate)
            ->where('slot_index', $request->slot_index)
            ->first();

        if ($request->action === 'undo') {
            if ($existing) $existing->delete();
            return response()->json(['success' => true, 'status' => 'pending']);
        }

        $data = [
            'care_task_type_id' => $plan->care_task_type_id,
            'status'            => $request->action,
            'done_at'           => now(),
            'done_by'           => auth()->id(),
            'notes'             => $request->notes,
        ];

        if ($existing) {
            $existing->update($data);
        } else {
            VaCareLog::create(array_merge($data, [
                'admission_id' => $admission->id,
                'care_plan_id' => $plan->id,
                'care_date'    => $careDate,
                'slot_index'   => $request->slot_index,
            ]));
        }

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

    // ── Vitals ───────────────────────────────────────────────────────────────

    public function storeVital(Request $request, $id)
    {
        if (!auth()->user()->can('vet_admission.log_care')) abort(403, 'Unauthorized action.');

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

        VaAdmissionVital::create([
            'admission_id'     => $admission->id,
            'recorded_at'      => $request->recorded_at ?: now(),
            'temperature'      => $request->temperature ?: null,
            'weight_kg'        => $request->weight_kg ?: null,
            'heart_rate'       => $request->heart_rate ?: null,
            'respiratory_rate' => $request->respiratory_rate ?: null,
            'notes'            => $request->notes,
            'recorded_by'      => auth()->id(),
        ]);

        return response()->json(['success' => true, 'msg' => __('vetAdmission::lang.vital_recorded')]);
    }

    // ── Flowsheet (treatment grid) ───────────────────────────────────────────

    /**
     * Render the per-admission flowsheet: rows = care-plan items, columns =
     * hourly slots within the chosen window (default: today). The grid loads
     * its data asynchronously from flowsheetData() and posts cell clicks
     * back through toggleCareLog().
     */
    public function flowsheet(Request $request, $id)
    {
        if (!$this->canView()) abort(403, 'Unauthorized action.');

        $admission = VaAdmission::with(['pet', 'owner', 'ward', 'attendingDoctor'])
            ->forBusiness($this->biz())->findOrFail($id);

        $defaultWindow = (int) ($request->window ?: 24);   // hours
        return view('vetAdmission::admissions.flowsheet', compact('admission', 'defaultWindow'));
    }

    /** AJAX: the matrix for the current window — feeds the grid renderer. */
    public function flowsheetData(Request $request, $id)
    {
        if (!$this->canView()) abort(403, 'Unauthorized action.');

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

        $from = $request->filled('from') ? Carbon::parse($request->from) : Carbon::today();
        $to   = $request->filled('to')   ? Carbon::parse($request->to)   : $from->copy()->endOfDay();
        // Defensive cap: never expand more than 7 days at once.
        if ($from->diffInDays($to) > 7) {
            $to = $from->copy()->addDays(7);
        }

        $matrix = app(CarePlanSlotService::class)->buildMatrix($admission, $from, $to);

        return response()->json([
            'from'   => $from->toIso8601String(),
            'to'     => $to->toIso8601String(),
            'now'    => now()->toIso8601String(),
            'rows'   => $matrix->values(),
        ]);
    }

    // ── Vital trends (M3) ────────────────────────────────────────────────────

    /**
     * Series + normal-range annotations for the admission's vital signs,
     * keyed by metric. Feeds the Chart.js panel on the admission show view.
     */
    public function vitalTrends(Request $request, $id)
    {
        if (!$this->canView()) abort(403, 'Unauthorized action.');
        $admission = VaAdmission::with('pet')->forBusiness($this->biz())->findOrFail($id);

        $rows = VaAdmissionVital::where('admission_id', $admission->id)
            ->orderBy('recorded_at')->get();

        $range = \Modules\VetClinic\Entities\VcVitalRange::resolve(
            (int) $this->biz(),
            optional($admission->pet)->species,
            optional($admission->pet)->age ? (int) $admission->pet->age : null
        );

        $points = $rows->map(function ($r) use ($range) {
            $point = [
                't'                  => $r->recorded_at?->toIso8601String(),
                'temperature'        => $r->temperature ? (float) $r->temperature : null,
                'heart_rate'         => $r->heart_rate ? (int) $r->heart_rate : null,
                'respiratory_rate'   => $r->respiratory_rate ? (int) $r->respiratory_rate : null,
                'weight_kg'          => $r->weight_kg ? (float) $r->weight_kg : null,
            ];
            $point['flags'] = $range
                ? $range->annotate($point)
                : ['temperature' => 'unknown', 'heart_rate' => 'unknown', 'respiratory_rate' => 'unknown', 'weight_kg' => 'unknown'];
            return $point;
        });

        return response()->json([
            'points' => $points->values(),
            'range'  => $range ? [
                'species'              => $range->species,
                'life_stage'           => $range->life_stage,
                'temperature_low'      => $range->temperature_low,
                'temperature_high'     => $range->temperature_high,
                'heart_rate_low'       => $range->heart_rate_low,
                'heart_rate_high'      => $range->heart_rate_high,
                'respiratory_rate_low' => $range->respiratory_rate_low,
                'respiratory_rate_high'=> $range->respiratory_rate_high,
            ] : null,
        ]);
    }

    /** Open alerts feed for the admission show banner. */
    public function alerts(Request $request, $id)
    {
        if (!$this->canView()) abort(403);
        $admission = VaAdmission::forBusiness($this->biz())->findOrFail($id);
        $alerts = \Modules\VetAdmission\Entities\VaAlert::where('admission_id', $admission->id)
            ->open()->orderByDesc('severity')->orderByDesc('raised_at')->get();
        return response()->json(['data' => $alerts]);
    }

    public function ackAlert(Request $request, $alertId)
    {
        if (!auth()->user()->can('vet_admission.log_care')) abort(403);
        $row = \Modules\VetAdmission\Entities\VaAlert::findOrFail($alertId);
        $admission = VaAdmission::forBusiness($this->biz())->findOrFail($row->admission_id);
        $row->update(['acknowledged_at' => now(), 'acknowledged_by' => auth()->id()]);
        return response()->json(['success' => true]);
    }
}
