<?php

namespace Modules\MedEmergency\Services;

use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Schema;
use Modules\MedEmergency\Entities\MderVisit;

/**
 * Admit hand-off to MedWard (SIFA P6-T3) — STRICTLY fail-soft.
 *
 * MedWard is being built in parallel and MUST NOT be a hard dependency. This
 * service NEVER references a MedWard class; it probes for the medward_admissions
 * table (Schema::hasTable) and, when present, inserts a pending admission row and
 * a deep-link to whichever MedWard route exists. When MedWard is absent the
 * disposition is simply recorded on the visit — no admission created, no error.
 *
 * @return array{ok: bool, admission_id: ?int, url: ?string, mode: string}
 *         mode ∈ {created, linked, unavailable}
 */
class WardHandoffService
{
    /**
     * Attempt to create / link a MedWard admission for an admitted ER visit.
     * Returns the outcome; the caller decides the board status from `ok`.
     */
    public function admit(MderVisit $visit): array
    {
        if (! $this->available()) {
            return ['ok' => false, 'admission_id' => null, 'url' => null, 'mode' => 'unavailable'];
        }

        try {
            $admissionId = $this->createAdmission($visit);

            return [
                'ok'           => (bool) $admissionId,
                'admission_id' => $admissionId,
                'url'          => $this->admissionUrl($admissionId),
                'mode'         => $admissionId ? 'created' : 'unavailable',
            ];
        } catch (\Throwable $e) {
            \Log::warning('MedEmergency ward hand-off skipped: ' . $e->getMessage());

            return ['ok' => false, 'admission_id' => null, 'url' => null, 'mode' => 'unavailable'];
        }
    }

    /** True only when MedWard's admissions table exists. */
    public function available(): bool
    {
        return Schema::hasTable('medward_admissions');
    }

    /**
     * Insert a pending admission row, populating only the columns MedWard's table
     * actually exposes (probed via Schema::hasColumn) so we never assume a schema
     * we do not own. Returns the new id, or null if the table shape is unusable.
     */
    private function createAdmission(MderVisit $visit): ?int
    {
        $cols = [];
        $has = fn ($c) => Schema::hasColumn('medward_admissions', $c);

        if ($has('business_id')) {
            $cols['business_id'] = $visit->business_id;
        }
        if ($has('patient_id')) {
            $cols['patient_id'] = $visit->patient_id;
        }
        if ($has('contact_id')) {
            $cols['contact_id'] = $visit->contact_id;
        }
        if ($has('patient_name')) {
            $cols['patient_name'] = $visit->patient_name;
        }
        if ($has('admission_type')) {
            $cols['admission_type'] = 'emergency';
        }
        if ($has('source')) {
            $cols['source'] = 'emergency';
        }
        if ($has('status')) {
            $cols['status'] = 'awaiting_bed';
        }
        if ($has('admitted_at')) {
            $cols['admitted_at'] = now();
        }
        if ($has('mder_visit_id')) {
            $cols['mder_visit_id'] = $visit->id;
        }
        if ($has('assigned_doctor_id')) {
            $cols['assigned_doctor_id'] = $visit->assigned_doctor_id;
        }
        if ($has('created_by')) {
            $cols['created_by'] = auth()->id();
        }
        if ($has('created_at')) {
            $cols['created_at'] = now();
        }
        if ($has('updated_at')) {
            $cols['updated_at'] = now();
        }

        // Nothing recognisable to write into → treat as unavailable.
        if (empty($cols['business_id']) && empty($cols['patient_id'])) {
            return null;
        }

        return (int) DB::table('medward_admissions')->insertGetId($cols);
    }

    /**
     * Best-effort deep link to the MedWard admission. Tries a small set of likely
     * route names; returns null if none are registered (the board still shows the
     * admission id without a link).
     */
    private function admissionUrl(?int $admissionId): ?string
    {
        if (! $admissionId) {
            return null;
        }

        foreach (['medward.admissions.show', 'medward.admission.show', 'medward.admissions.edit'] as $name) {
            if (Route::has($name)) {
                try {
                    return route($name, $admissionId);
                } catch (\Throwable $e) {
                    // try the next candidate
                }
            }
        }

        return null;
    }
}
