<?php

namespace Modules\ClinicCore\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\DB;
use Modules\ClinicCore\Entities\ClcOrder;
use Modules\ClinicCore\Entities\ClcOrderItem;
use Modules\ClinicCore\Entities\ClcPatient;
use Modules\ClinicCore\Entities\Services\MedicalAlertService;
use Modules\ClinicCore\Entities\Services\OrderRoutingService;
use Modules\ClinicCore\Events\ClcOrderPlaced;
use Yajra\DataTables\Facades\DataTables;

/**
 * SIFA P3-T6 — unified clinical orders (lab / imaging / procedure / consultation).
 * Placement routes to the existing downstream flows (imaging requests / lab
 * worklist) via OrderRoutingService, fires ClcOrderPlaced, and warns (non-block)
 * on same-day duplicates. Every action is business-scoped + permission-gated.
 */
class ClcOrderController extends Controller
{
    use \Modules\ClinicCore\Http\Controllers\Traits\LogsClcActivity;

    private function biz(): int
    {
        return (int) request()->session()->get('user.business_id');
    }

    public function index()
    {
        if (!auth()->user()->can('clinic.order.view') && !auth()->user()->can('clinic.order.create')) {
            abort(403, 'Unauthorized action.');
        }

        return view('clinicCore::orders.index');
    }

    public function list(Request $request)
    {
        if (!auth()->user()->can('clinic.order.view') && !auth()->user()->can('clinic.order.create')) {
            abort(403, 'Unauthorized action.');
        }

        $businessId = $this->biz();
        $query = ClcOrder::with(['patient:id,patient_name,species', 'doctor:id,name'])
            ->withCount('items')
            ->where('business_id', $businessId);

        if ($request->filled('filter_type')) {
            $query->where('order_type', $request->filter_type);
        }
        if ($request->filled('filter_status')) {
            $query->where('status', $request->filter_status);
        }
        if ($request->filled('filter_priority')) {
            $query->where('priority', $request->filter_priority);
        }
        if ($request->filled('filter_search')) {
            $term = $request->filter_search;
            $query->where(function ($q) use ($term) {
                $q->where('order_no', 'like', '%' . $term . '%')
                  ->orWhereHas('patient', fn($sq) => $sq->where('patient_name', 'like', '%' . $term . '%'));
            });
        }

        $dateFormat = session('business.date_format', 'd M Y');

        return DataTables::of($query)
            ->addColumn('order_no_col', fn($row) => '<a href="#" class="clc-order-view" data-id="' . $row->id . '" style="font-weight:700;font-family:monospace;color:#475569;">' . e($row->order_no) . '</a>')
            ->addColumn('patient_name', function ($row) {
                if (!$row->patient) return '—';
                return '<a href="' . route('clinic.patients.show', $row->patient->id) . '" style="font-weight:600;">' . e($row->patient->patient_name) . '</a>';
            })
            ->addColumn('type_badge', function ($row) {
                $colors = ['lab' => 'info', 'imaging' => 'primary', 'procedure' => 'warning', 'consultation' => 'default'];
                return '<span class="label label-' . ($colors[$row->order_type] ?? 'default') . '">' . e(ucfirst($row->order_type)) . '</span>';
            })
            ->addColumn('priority_badge', function ($row) {
                $colors = ['routine' => 'default', 'urgent' => 'warning', 'stat' => 'danger'];
                return '<span class="label label-' . ($colors[$row->priority] ?? 'default') . '">' . e(ucfirst($row->priority)) . '</span>';
            })
            ->addColumn('status_badge', function ($row) {
                $colors = [
                    'ordered' => 'default', 'collected' => 'info', 'in_progress' => 'warning',
                    'resulted' => 'primary', 'verified' => 'success', 'cancelled' => 'danger',
                ];
                return '<span class="label label-' . ($colors[$row->status] ?? 'default') . '">' . e(ucfirst(str_replace('_', ' ', $row->status))) . '</span>';
            })
            ->addColumn('created_col', fn($row) => $row->created_at ? $row->created_at->format($dateFormat) : '—')
            ->addColumn('action', function ($row) {
                $view  = '<button class="btn btn-xs btn-info clc-order-view" data-id="' . $row->id . '" title="View"><i class="fa fa-eye"></i></button> ';
                $print = '<a href="' . route('clinic.orders.print', $row->id) . '" target="_blank" class="btn btn-xs btn-default" title="Print"><i class="fa fa-print"></i></a>';
                return $view . $print;
            })
            ->rawColumns(['order_no_col', 'patient_name', 'type_badge', 'priority_badge', 'status_badge', 'action'])
            ->make(true);
    }

    /**
     * Detect same-day duplicates for a patient: same service_name + same
     * order_type ordered today. Non-blocking — returned as a warning list.
     */
    private function duplicateWarnings(int $businessId, int $patientId, string $orderType, array $serviceNames): array
    {
        $names = array_values(array_unique(array_filter(array_map(fn($n) => trim((string) $n), $serviceNames))));
        if (empty($names)) {
            return [];
        }

        $existing = ClcOrderItem::query()
            ->join('clc_orders as o', 'o.id', '=', 'clc_order_items.order_id')
            ->where('o.business_id', $businessId)
            ->where('o.patient_id', $patientId)
            ->where('o.order_type', $orderType)
            ->whereDate('o.created_at', now()->toDateString())
            ->pluck('clc_order_items.service_name')
            ->map(fn($v) => mb_strtolower(trim((string) $v)))
            ->unique();

        $warnings = [];
        foreach ($names as $n) {
            if ($existing->contains(mb_strtolower($n))) {
                $warnings[] = __('clinicCore::lang.order_duplicate_warning', ['service' => $n]);
            }
        }
        return $warnings;
    }

    public function store(Request $request)
    {
        if (!auth()->user()->can('clinic.order.create')) {
            return response()->json(['success' => false, 'msg' => 'Unauthorized'], 403);
        }

        $request->validate([
            'patient_id'          => 'required|integer',
            'appointment_id'      => 'nullable|integer',
            'ordering_doctor_id'  => 'nullable|integer',
            'order_type'          => 'required|in:lab,imaging,procedure,consultation',
            'priority'            => 'nullable|in:routine,urgent,stat',
            'clinical_indication' => 'nullable|string|max:2000',
            'items'                 => 'required|array|min:1',
            'items.*.service_name'  => 'required|string|max:200',
            'items.*.service_code'  => 'nullable|string|max:60',
            'items.*.laterality'    => 'nullable|in:left,right,bilateral,na',
            'items.*.quantity'      => 'nullable|integer|min:1',
        ]);

        $businessId = $this->biz();
        $patient = ClcPatient::where('business_id', $businessId)->findOrFail($request->patient_id);

        $serviceNames = collect($request->items)->pluck('service_name')->all();
        $duplicates = $this->duplicateWarnings($businessId, (int) $patient->id, $request->order_type, $serviceNames);

        $order = DB::transaction(function () use ($request, $businessId, $patient) {
            $order = ClcOrder::create([
                'business_id'         => $businessId,
                'order_no'            => ClcOrder::nextOrderNo($businessId),
                'appointment_id'      => $request->appointment_id,
                'patient_id'          => $patient->id,
                'ordering_doctor_id'  => $request->ordering_doctor_id,
                'order_type'          => $request->order_type,
                'priority'            => $request->priority ?: 'routine',
                'clinical_indication' => $request->clinical_indication,
                'status'              => 'ordered',
            ]);

            foreach ($request->items as $it) {
                ClcOrderItem::create([
                    'order_id'     => $order->id,
                    'service_name' => $it['service_name'],
                    'service_code' => $it['service_code'] ?? null,
                    'laterality'   => $it['laterality'] ?? 'na',
                    'quantity'     => $it['quantity'] ?? 1,
                    'status'       => 'ordered',
                ]);
            }

            return $order;
        });

        // Route to the downstream flows (imaging requests / lab worklist).
        // Fail-soft inside the service — never blocks the saved order.
        $routing = app(OrderRoutingService::class)->route($order);

        // Fire the event for future modules (fail-soft).
        try {
            event(new ClcOrderPlaced($order->fresh('items')));
        } catch (\Throwable $e) {
            \Log::warning('ClcOrderPlaced dispatch skipped: ' . $e->getMessage());
        }

        $this->drmLog('create', $order, ['note' => 'Order (' . $order->order_type . ') with ' . count($request->items) . ' item(s)']);

        return response()->json([
            'success'    => true,
            'msg'        => __('clinicCore::lang.order_placed'),
            'order_id'   => $order->id,
            'order_no'   => $order->order_no,
            'warnings'   => $duplicates,
            'routing'    => $routing,
            'print_url'  => route('clinic.orders.print', $order->id),
        ]);
    }

    /** JSON payload for the view modal (items + downstream links). */
    public function show(Request $request, $id)
    {
        if (!auth()->user()->can('clinic.order.view') && !auth()->user()->can('clinic.order.create')) {
            abort(403, 'Unauthorized action.');
        }

        $order = ClcOrder::with(['items', 'patient:id,patient_name,species', 'doctor:id,name'])
            ->where('business_id', $this->biz())->findOrFail($id);

        return response()->json([
            'success' => true,
            'order'   => [
                'id'                  => $order->id,
                'order_no'            => $order->order_no,
                'order_type'          => $order->order_type,
                'priority'            => $order->priority,
                'status'              => $order->status,
                'clinical_indication' => $order->clinical_indication,
                'patient_name'        => optional($order->patient)->patient_name,
                'doctor_name'         => optional($order->doctor)->name,
                'verified_at'         => optional($order->verified_at)->format('d M Y H:i'),
                'created_at'          => optional($order->created_at)->format('d M Y H:i'),
                'can_verify'          => auth()->user()->can('clinic.order.verify') && $order->status !== 'verified' && $order->status !== 'cancelled',
                'items'               => $order->items->map(fn($i) => [
                    'id'              => $i->id,
                    'service_name'    => $i->service_name,
                    'service_code'    => $i->service_code,
                    'laterality'      => $i->laterality,
                    'quantity'        => $i->quantity,
                    'status'          => $i->status,
                    'result_summary'  => $i->result_summary,
                    'abnormal_flag'   => $i->abnormal_flag,
                    'downstream_type' => $i->downstream_type,
                    'note'            => $i->note,
                ])->values(),
            ],
        ]);
    }

    /**
     * Update a single item (result summary / abnormal flag / status). Rolls the
     * status up to the header and raises a critical_value alert when a critical
     * abnormal flag is recorded (idempotent per item).
     */
    public function updateItem(Request $request, $itemId)
    {
        if (!auth()->user()->can('clinic.order.create') && !auth()->user()->can('clinic.order.verify')) {
            return response()->json(['success' => false, 'msg' => 'Unauthorized'], 403);
        }

        $request->validate([
            'status'         => 'nullable|in:ordered,in_progress,resulted,cancelled',
            'result_summary' => 'nullable|string|max:2000',
            'abnormal_flag'  => 'nullable|in:normal,high,low,critical_high,critical_low',
        ]);

        $item = ClcOrderItem::with('order')->findOrFail($itemId);
        $order = $item->order;
        if (!$order || $order->business_id != $this->biz()) {
            abort(404);
        }

        if ($request->filled('status'))         $item->status = $request->status;
        if ($request->has('result_summary'))    $item->result_summary = $request->result_summary;
        if ($request->has('abnormal_flag'))     $item->abnormal_flag = $request->abnormal_flag ?: null;
        $item->save();

        // Critical value → medical alert (idempotent per item via source link).
        if ($item->isCritical()) {
            try {
                app(MedicalAlertService::class)->raise([
                    'business_id' => (int) $order->business_id,
                    'patient_id'  => (int) $order->patient_id,
                    'alert_type'  => 'critical_value',
                    'severity'    => 'critical',
                    'title'       => trim(__('clinicCore::lang.order_critical_alert_title', ['service' => $item->service_name])),
                    'details'     => $item->result_summary ?: null,
                    'source_type' => 'clc_order_items',
                    'source_id'   => (int) $item->id,
                ]);
            } catch (\Throwable $e) {
                \Log::warning('ClcOrder critical alert raise skipped: ' . $e->getMessage());
            }
        }

        $order->rollUpStatus();
        $this->drmLog('update', $order, ['action' => 'item_updated', 'item_id' => $item->id, 'status' => $item->status]);

        return response()->json([
            'success'      => true,
            'msg'          => __('clinicCore::lang.updated_successfully'),
            'order_status' => $order->fresh()->status,
            'item_status'  => $item->status,
        ]);
    }

    /** Verify order results — final sign-off. */
    public function verify(Request $request, $id)
    {
        if (!auth()->user()->can('clinic.order.verify')) {
            return response()->json(['success' => false, 'msg' => 'Unauthorized'], 403);
        }

        $order = ClcOrder::where('business_id', $this->biz())->findOrFail($id);
        if ($order->status === 'cancelled') {
            return response()->json(['success' => false, 'msg' => __('clinicCore::lang.order_cannot_verify_cancelled')], 422);
        }

        $order->update([
            'status'      => 'verified',
            'verified_by' => auth()->id(),
            'verified_at' => now(),
        ]);
        $this->drmLog('update', $order, ['action' => 'verified']);

        return response()->json([
            'success'     => true,
            'msg'         => __('clinicCore::lang.order_verified'),
            'verified_at' => $order->verified_at->format('d M Y H:i'),
        ]);
    }

    public function print($id)
    {
        if (!auth()->user()->can('clinic.order.view') && !auth()->user()->can('clinic.order.create')) {
            abort(403, 'Unauthorized action.');
        }

        $businessId = $this->biz();
        $order = ClcOrder::with(['items', 'patient', 'doctor', 'appointment'])
            ->where('business_id', $businessId)->findOrFail($id);
        $business = \App\Business::findOrFail($businessId);

        return view('clinicCore::orders.print', compact('order', 'business'));
    }
}
