<?php

namespace Modules\VetClinic\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\DB;
use Modules\VetClinic\Entities\VcAppointment;
use Modules\VetClinic\Entities\VcAppointmentExamFinding;
use Modules\VetClinic\Entities\VcExamSetting;
use Modules\VetClinic\Entities\VcExamTemplate;
use Modules\VetClinic\Entities\VcExamTemplateItem;

/**
 * Item 1.4 - structured exam UI on the appointment Objective tab.
 *
 *  GET  /vet-clinic/appointments/{id}/exam/templates
 *       -> list active templates available for this appointment's species
 *  GET  /vet-clinic/appointments/{id}/exam/findings?template_id=...
 *       -> all findings for an appointment, optionally scoped to one template
 *  POST /vet-clinic/appointments/{id}/exam/findings
 *       -> upsert a single finding (one auto-save call per widget change)
 *  DELETE /vet-clinic/appointments/{id}/exam/findings/{findingId}
 *       -> remove a finding (rarely used; the UI mostly upserts to '')
 *
 * Severity + is_critical are computed server-side from the template item's
 * scoreValue() so the Medical Critical Check report (item 4.1) can trust
 * a flat WHERE is_critical = 1 without re-evaluating template logic.
 */
class VcExamController extends Controller
{
    private function bizId(): int
    {
        return (int) request()->session()->get('user.business_id');
    }

    private function guardRecord(): void
    {
        if (!auth()->user()->can('vet_clinic.record_exam_findings')
            && !auth()->user()->can('vet_clinic.manage_appointments')) {
            abort(403, 'Not authorised to record exam findings.');
        }
    }

    private function guardView(): void
    {
        if (!auth()->user()->can('vet_clinic.view_exam_findings')
            && !auth()->user()->can('vet_clinic.record_exam_findings')
            && !auth()->user()->can('vet_clinic.manage_appointments')) {
            abort(403, 'Not authorised to view exam findings.');
        }
    }

    /** Loads the appointment, enforcing business-scope. */
    private function appt(int $id): VcAppointment
    {
        return VcAppointment::where('business_id', $this->bizId())->findOrFail($id);
    }

    /**
     * GET ../exam/templates
     * Returns the active general template + all active specialist templates
     * filtered by species, honouring the per-business exam settings.
     */
    public function templates(int $appointmentId)
    {
        $this->guardView();
        $appt = $this->appt($appointmentId);
        $species = strtolower(optional($appt->pet)->species ?? '');

        $settings = VcExamSetting::forBusiness($this->bizId());

        // General: prefer the business's explicit choice, fall back to any
        // active general template for the species.
        $general = null;
        if ($settings->active_general_template_id) {
            $general = VcExamTemplate::active()
                ->forBusiness($this->bizId())
                ->where('id', $settings->active_general_template_id)
                ->first();
        }
        if (!$general) {
            $general = VcExamTemplate::active()->general()
                ->forBusiness($this->bizId())
                ->forSpecies($species)
                ->orderBy('sort_order')->orderBy('id')
                ->first();
        }

        $specialistQuery = VcExamTemplate::active()->specialist()
            ->forBusiness($this->bizId())
            ->forSpecies($species)
            ->orderBy('sort_order')->orderBy('display_label');

        if (is_array($settings->visible_specialist_template_ids)
            && count($settings->visible_specialist_template_ids)) {
            $specialistQuery->whereIn('id', $settings->visible_specialist_template_ids);
        }
        $specialists = $specialistQuery->get();

        return response()->json([
            'success'     => true,
            'general'     => $this->serialiseTemplate($general),
            'specialists' => $specialists->map(fn($t) => $this->serialiseTemplate($t))->values(),
        ]);
    }

    /**
     * GET ../exam/findings?template_id=...
     * Returns all findings for this appointment, optionally scoped.
     */
    public function findings(int $appointmentId, Request $request)
    {
        $this->guardView();
        $this->appt($appointmentId);

        $q = VcAppointmentExamFinding::forAppointment($appointmentId)
            ->where('business_id', $this->bizId());
        if ($request->filled('template_id')) {
            $q->where('template_id', (int) $request->template_id);
        }
        $rows = $q->get()->map(function ($f) {
            return [
                'id'                => $f->id,
                'template_id'       => $f->template_id,
                'template_item_id'  => $f->template_item_id,
                'region'            => $f->region_snapshot,
                'item_label'        => $f->item_label_snapshot,
                'side'              => $f->side,
                'value'             => $f->value,
                'numeric_value'     => $f->numeric_value,
                'values_json'       => $f->values_json,
                'free_text'         => $f->free_text,
                'severity'          => $f->severity,
                'is_critical'       => (bool) $f->is_critical,
            ];
        });
        return response()->json(['success' => true, 'findings' => $rows]);
    }

    /**
     * POST ../exam/findings
     * Body: template_item_id, side?, value?, values_json?, free_text?
     *
     * Upsert by (appointment_id, template_item_id, side). An empty value
     * + empty values_json + empty free_text deletes the row (cleaner than
     * keeping empty findings around for the critical-check report).
     */
    public function saveFinding(int $appointmentId, Request $request)
    {
        $this->guardRecord();
        $appt = $this->appt($appointmentId);

        $request->validate([
            'template_item_id' => 'required|integer|exists:vc_exam_template_items,id',
            'side'             => 'nullable|string|max:8',
            'value'            => 'nullable|string|max:500',
            'values_json'      => 'nullable|array',
            'free_text'        => 'nullable|string|max:2000',
        ]);

        $item = VcExamTemplateItem::with('template')->findOrFail($request->template_item_id);

        // Empty submission removes the existing finding for this slot.
        $hasValue = $request->filled('value')
            || $request->filled('free_text')
            || (is_array($request->values_json) && count($request->values_json));
        if (!$hasValue) {
            VcAppointmentExamFinding::where('appointment_id', $appointmentId)
                ->where('template_item_id', $item->id)
                ->where('side', $request->input('side'))
                ->delete();
            return response()->json(['success' => true, 'deleted' => true]);
        }

        $valueForScoring = $request->filled('value')
            ? $request->value
            : (is_array($request->values_json) ? $request->values_json : null);
        $score = $item->scoreValue($valueForScoring);

        $finding = VcAppointmentExamFinding::updateOrCreate(
            [
                'appointment_id'   => $appointmentId,
                'template_item_id' => $item->id,
                'side'             => $request->input('side'),
            ],
            [
                'business_id'        => $this->bizId(),
                'template_id'        => $item->template_id,
                'region_snapshot'    => $item->region,
                'item_label_snapshot'=> $item->item_label,
                'value'              => $request->value,
                'numeric_value'      => $score['numeric'],
                'values_json'        => $request->values_json,
                'free_text'          => $request->free_text,
                'severity'           => $score['severity'],
                'is_critical'        => $score['is_critical'],
                'recorded_by'        => auth()->id(),
            ]
        );

        return response()->json([
            'success'     => true,
            'id'          => $finding->id,
            'severity'    => $finding->severity,
            'is_critical' => (bool) $finding->is_critical,
        ]);
    }

    /**
     * DELETE ../exam/findings/{findingId}
     */
    public function deleteFinding(int $appointmentId, int $findingId)
    {
        $this->guardRecord();
        $this->appt($appointmentId);

        VcAppointmentExamFinding::where('id', $findingId)
            ->where('appointment_id', $appointmentId)
            ->where('business_id', $this->bizId())
            ->delete();

        return response()->json(['success' => true]);
    }

    /** Compact JSON shape used by both UI and the report consumer. */
    private function serialiseTemplate(?VcExamTemplate $tpl): ?array
    {
        if (!$tpl) return null;
        return [
            'id'            => $tpl->id,
            'name'          => $tpl->name,
            'kind'          => $tpl->kind,
            'display_label' => $tpl->display_label ?: $tpl->name,
            'icon'          => $tpl->icon,
            'colour'        => $tpl->colour,
            'items'         => $tpl->items->map(function ($i) {
                return [
                    'id'              => $i->id,
                    'region'          => $i->region,
                    'item_label'      => $i->item_label,
                    'response_type'   => $i->response_type,
                    'options_json'    => $i->options_json,
                    'unit'            => $i->unit,
                    'normal_low'      => $i->normal_low,
                    'normal_high'     => $i->normal_high,
                    'critical_low'    => $i->critical_low,
                    'critical_high'   => $i->critical_high,
                    'lateralisation'  => $i->lateralisation,
                    'is_required'     => (bool) $i->is_required,
                    'sort_order'      => $i->sort_order,
                    'help_text'       => $i->help_text,
                ];
            })->values(),
        ];
    }
}
