<?php

namespace Modules\ClinicCore\Entities\Services;

use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Modules\ClinicCore\Entities\ClcImagingModality;
use Modules\ClinicCore\Entities\ClcImagingRequest;
use Modules\ClinicCore\Entities\ClcOrder;
use Modules\ClinicCore\Entities\ClcOrderItem;
use Modules\ClinicCore\Entities\ClcPatient;

/**
 * SIFA P3-T6 — routes a placed order to the existing downstream flows:
 *
 *   imaging → create a clc_imaging_requests row per item.
 *   lab     → when ClinicLab/LabCore installed, insert a lab_worklist row per
 *             item (via DB::table, no model dependency); else leave the item
 *             `ordered` with a note.
 *   procedure / consultation → stay internal (no routing).
 *
 * EVERY routing branch is fail-soft: a failure stamps the item's note and never
 * blocks saving the order. downstream_type/downstream_id are saved back onto the
 * item so the order can be tracked to its downstream record.
 */
class OrderRoutingService
{
    /**
     * Route every item of the given order. Mutates + saves the items in place.
     * Returns a short per-item routing summary (for logging / the response).
     *
     * @return array<int, array{item_id:int, downstream_type:?string, downstream_id:?int, note:?string}>
     */
    public function route(ClcOrder $order): array
    {
        $order->loadMissing('items');
        $summary = [];

        foreach ($order->items as $item) {
            switch ($order->order_type) {
                case 'imaging':
                    $this->routeImaging($order, $item);
                    break;
                case 'lab':
                    $this->routeLab($order, $item);
                    break;
                default:
                    // procedure / consultation stay internal — nothing to route.
                    break;
            }

            $summary[] = [
                'item_id'         => (int) $item->id,
                'downstream_type' => $item->downstream_type,
                'downstream_id'   => $item->downstream_id ? (int) $item->downstream_id : null,
                'note'            => $item->note,
            ];
        }

        return $summary;
    }

    /** imaging → one clc_imaging_requests row per item. */
    protected function routeImaging(ClcOrder $order, ClcOrderItem $item): void
    {
        try {
            if (!Schema::hasTable('clc_imaging_requests')) {
                $item->note = __('clinicCore::lang.order_routing_imaging_absent');
                $item->save();
                return;
            }

            $patient = ClcPatient::where('business_id', $order->business_id)->find($order->patient_id);
            $modalityId = $this->resolveModalityId((int) $order->business_id);
            if (!$modalityId) {
                $item->note = __('clinicCore::lang.order_routing_no_modality');
                $item->save();
                return;
            }

            $req = ClcImagingRequest::create([
                'business_id'    => $order->business_id,
                'ref_no'         => ClcImagingRequest::nextRefNo((int) $order->business_id),
                'patient_id'     => $order->patient_id,
                'contact_id'     => $patient->contact_id ?? null,
                'appointment_id' => $order->appointment_id,
                'modality_id'    => $modalityId,
                'body_region'    => mb_substr((string) $item->service_name, 0, 120),
                'indication'     => $order->clinical_indication,
                'priority'       => $this->mapPriority($order->priority),
                'status'         => 'requested',
                'requested_by'   => $order->ordering_doctor_id ? null : auth()->id(),
                'requested_at'   => now(),
            ]);

            $item->downstream_type = 'clc_imaging_requests';
            $item->downstream_id   = $req->id;
            $item->note            = null;
            $item->save();
        } catch (\Throwable $e) {
            \Log::warning('OrderRoutingService imaging routing failed: ' . $e->getMessage());
            $item->note = __('clinicCore::lang.order_routing_failed');
            $item->save();
        }
    }

    /** lab → one lab_worklist row per item (only when ClinicLab/LabCore present). */
    protected function routeLab(ClcOrder $order, ClcOrderItem $item): void
    {
        try {
            $mu = app(\App\Utils\ModuleUtil::class);
            $labReady = ($mu->isModuleInstalled('ClinicLab') || $mu->isModuleInstalled('LabCore'))
                && Schema::hasTable('lab_worklist');

            if (!$labReady) {
                // Leave the item in `ordered` with an explanatory note.
                $item->note = __('clinicCore::lang.order_routing_lab_absent');
                $item->save();
                return;
            }

            $patient   = ClcPatient::where('business_id', $order->business_id)->find($order->patient_id);
            $sampleNo  = $order->order_no . '-' . $item->id;

            $row = [
                'business_id'  => $order->business_id,
                'vendor'       => 'manual',
                'sample_no'    => mb_substr($sampleNo, 0, 30),
                'patient_id'   => (string) $order->patient_id,
                'patient_name' => $patient ? ($patient->patient_name ?: null) : null,
                'tests'        => json_encode([$item->service_code ?: $item->service_name]),
                'status'       => 'pending',
                'contact_id'   => $patient->contact_id ?? null,
                'created_by'   => auth()->id(),
                'created_at'   => now(),
                'updated_at'   => now(),
            ];

            // Clinic linkage columns exist only once the ClinicLab bridge migration
            // has run — set them conditionally so we never reference a missing col.
            if (Schema::hasColumn('lab_worklist', 'clc_patient_id')) {
                $row['clc_patient_id'] = $order->patient_id;
            }
            if (Schema::hasColumn('lab_worklist', 'clc_appointment_id')) {
                $row['clc_appointment_id'] = $order->appointment_id;
            }

            $id = DB::table('lab_worklist')->insertGetId($row);

            $item->downstream_type = 'lab_worklist';
            $item->downstream_id   = $id;
            $item->note            = null;
            $item->save();
        } catch (\Throwable $e) {
            \Log::warning('OrderRoutingService lab routing failed: ' . $e->getMessage());
            $item->note = __('clinicCore::lang.order_routing_failed');
            $item->save();
        }
    }

    /**
     * Pick a modality for a routed imaging request: the business's first active
     * modality, falling back to a system-default (business_id NULL) modality.
     */
    protected function resolveModalityId(int $businessId): ?int
    {
        $id = ClcImagingModality::forBusiness($businessId)
            ->where('status', 'active')
            ->orderByRaw('CASE WHEN business_id IS NULL THEN 1 ELSE 0 END')
            ->orderBy('sort_order')
            ->value('id');

        return $id ? (int) $id : null;
    }

    /** Order priority (routine/urgent/stat) → imaging priority (same enum). */
    protected function mapPriority(?string $priority): string
    {
        return in_array($priority, ['routine', 'urgent', 'stat'], true) ? $priority : 'routine';
    }
}
