<?php

namespace Modules\MedWard\Database\Seeders;

use Carbon\Carbon;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Modules\MedWard\Entities\MedwardAdmission;
use Modules\MedWard\Entities\MedwardBed;
use Modules\MedWard\Entities\MedwardBedAssignment;
use Modules\MedWard\Entities\MedwardFluidBalance;
use Modules\MedWard\Entities\MedwardIcuFlowsheet;
use Modules\MedWard\Entities\MedwardMarEntry;
use Modules\MedWard\Entities\MedwardWard;
use Modules\MedWard\Services\IcuService;

/**
 * Demo data for the business named 'Shifa One' only (skips silently elsewhere).
 * Uses EXISTING demo data — never invents patients/appointments.
 *
 * Seeds:
 *   - 2 wards: General (6 beds) + ICU (3 beds).
 *   - 1 active admission in General with generated MAR entries + fluid rows.
 *   - 1 active ICU admission with 2 flow-sheet rows (the second breaches MAP so it
 *     also raises an idempotent critical_value alert via IcuService).
 *
 * Everything is idempotent (firstOrCreate keyed on natural columns) so repair /
 * re-runs never duplicate. All ClinicCore integration is fail-soft.
 */
class MedwardDemoSeeder extends Seeder
{
    public function run(): void
    {
        if (! Schema::hasTable('business') || ! Schema::hasTable('medward_wards')) {
            return;
        }

        $business = DB::table('business')->where('name', 'Shifa One')->first();
        if (empty($business)) {
            return; // not the Shifa host / demo DB — skip silently
        }

        $businessId = (int) $business->id;

        // ── Wards + beds ────────────────────────────────────────────────────
        $general = MedwardWard::firstOrCreate(
            ['business_id' => $businessId, 'code' => 'GEN-A'],
            ['name' => 'General Ward A', 'ward_type' => 'general', 'floor' => '1', 'is_active' => true]
        );
        $icu = MedwardWard::firstOrCreate(
            ['business_id' => $businessId, 'code' => 'ICU-1'],
            ['name' => 'ICU', 'ward_type' => 'icu', 'floor' => '2', 'is_active' => true]
        );

        $this->makeBeds($businessId, $general, 6, 'G');
        $this->makeBeds($businessId, $icu, 3, 'I', 'electric');
        $general->update(['total_beds' => MedwardBed::where('ward_id', $general->id)->count()]);
        $icu->update(['total_beds' => MedwardBed::where('ward_id', $icu->id)->count()]);

        // ── Patients (reuse existing) ───────────────────────────────────────
        if (! Schema::hasTable('clc_patients')) {
            $this->report('MedWard demo: wards + beds seeded ("Shifa One") — ClinicCore absent, no admissions.');

            return;
        }

        $patients = DB::table('clc_patients')
            ->where('business_id', $businessId)
            ->orderBy('id')->limit(2)
            ->get(['id', 'contact_id']);

        if ($patients->count() < 1) {
            $this->report('MedWard demo: wards + beds seeded (no patients — no admissions).');

            return;
        }

        // ── Active General admission + MAR + fluid ─────────────────────────
        $p1 = $patients->first();
        $genBed = MedwardBed::where('ward_id', $general->id)->orderBy('bed_number')->first();

        $adm1 = MedwardAdmission::firstOrCreate(
            ['business_id' => $businessId, 'patient_id' => (int) $p1->id, 'ward_id' => $general->id, 'status' => 'admitted'],
            [
                'admission_no'        => MedwardAdmission::nextAdmissionNo($businessId),
                'contact_id'          => (int) $p1->contact_id,
                'bed_id'              => $genBed->id,
                'admission_type'      => 'elective',
                'admission_source'    => 'outpatient',
                'admitting_diagnosis' => 'Community-acquired pneumonia (demo)',
                'admitted_at'         => Carbon::now()->subDays(2),
                'expected_discharge'  => Carbon::now()->addDays(3),
                'is_icu'              => false,
            ]
        );
        $this->occupy($genBed, $adm1);

        // Seed 3 MAR entries directly (demo: independent of a live Rx).
        $slots = [['08:00', 'Amoxicillin', '500 mg', 'PO'], ['14:00', 'Paracetamol', '1 g', 'PO'], ['20:00', 'Amoxicillin', '500 mg', 'PO']];
        foreach ($slots as $s) {
            MedwardMarEntry::firstOrCreate(
                ['business_id' => $businessId, 'admission_id' => $adm1->id, 'medicine_name' => $s[1], 'scheduled_at' => Carbon::today()->setTimeFromTimeString($s[0])],
                ['status' => 'scheduled', 'dose' => $s[2], 'route' => $s[3]]
            );
        }

        MedwardFluidBalance::firstOrCreate(
            ['business_id' => $businessId, 'admission_id' => $adm1->id, 'shift' => 'morning', 'recorded_at' => Carbon::today()->setTime(12, 0)],
            ['intake_oral' => 400, 'intake_iv' => 500, 'output_urine' => 650]
        );
        MedwardFluidBalance::firstOrCreate(
            ['business_id' => $businessId, 'admission_id' => $adm1->id, 'shift' => 'evening', 'recorded_at' => Carbon::today()->setTime(20, 0)],
            ['intake_oral' => 300, 'intake_iv' => 500, 'output_urine' => 700, 'output_drain' => 50]
        );

        // ── Active ICU admission + 2 flow-sheets ───────────────────────────
        $p2 = $patients->count() > 1 ? $patients->get(1) : $patients->first();
        $icuBed = MedwardBed::where('ward_id', $icu->id)->orderBy('bed_number')->first();

        $adm2 = MedwardAdmission::firstOrCreate(
            ['business_id' => $businessId, 'patient_id' => (int) $p2->id, 'ward_id' => $icu->id, 'status' => 'admitted'],
            [
                'admission_no'        => MedwardAdmission::nextAdmissionNo($businessId),
                'contact_id'          => (int) $p2->contact_id,
                'bed_id'              => $icuBed->id,
                'admission_type'      => 'emergency',
                'admission_source'    => 'er',
                'admitting_diagnosis' => 'Septic shock (demo)',
                'admitted_at'         => Carbon::now()->subDay(),
                'is_icu'              => true,
                'icu_type'            => 'medical',
                'apache_ii'           => 18,
                'sofa'                => 7,
                'ventilator'          => true,
                'ventilator_mode'     => 'SIMV',
            ]
        );
        $this->occupy($icuBed, $adm2);

        // Two flow-sheets via IcuService so MAP auto-calcs and the low-MAP row
        // raises the demo critical_value alert. Guarded so re-runs don't stack.
        if ($adm2->flowsheets()->count() === 0) {
            $svc = app(IcuService::class);
            $svc->chart($adm2, ['recorded_at' => Carbon::now()->subHours(6), 'gcs_total' => 12, 'rass' => -1, 'hr' => 98, 'bp_sys' => 118, 'bp_dia' => 72, 'spo2' => 96, 'rr' => 18, 'temp' => 38.4, 'fio2' => 40, 'peep' => 5]);
            // Second row deliberately hypotensive (MAP < 60) to demo the alert.
            $svc->chart($adm2, ['recorded_at' => Carbon::now()->subHour(), 'gcs_total' => 11, 'rass' => -2, 'hr' => 122, 'bp_sys' => 78, 'bp_dia' => 44, 'spo2' => 88, 'rr' => 26, 'temp' => 38.9, 'fio2' => 60, 'peep' => 8, 'interventions' => 'Noradrenaline started']);
        }

        $this->report('MedWard demo: 2 wards (General 6 + ICU 3 beds), 1 active admission (MAR + fluids), 1 ICU admission (2 flow-sheets) seeded for "Shifa One".');
    }

    /** Create N sequential beds for a ward, idempotently. */
    private function makeBeds(int $businessId, MedwardWard $ward, int $count, string $prefix, string $type = 'standard'): void
    {
        for ($i = 1; $i <= $count; $i++) {
            MedwardBed::firstOrCreate(
                ['ward_id' => $ward->id, 'bed_number' => $prefix . '-' . str_pad((string) $i, 2, '0', STR_PAD_LEFT)],
                ['business_id' => $businessId, 'bed_type' => $type, 'status' => 'available', 'cleaning_status' => 'clean']
            );
        }
    }

    /** Mark a bed occupied by an admission + ensure an open bed-assignment row. */
    private function occupy(MedwardBed $bed, MedwardAdmission $admission): void
    {
        if ((int) $bed->current_admission_id !== (int) $admission->id) {
            $bed->update(['status' => 'occupied', 'current_admission_id' => $admission->id]);
        }
        MedwardBedAssignment::firstOrCreate(
            ['admission_id' => $admission->id, 'bed_id' => $bed->id, 'released_at' => null],
            ['assigned_at' => $admission->admitted_at ?: now(), 'reason' => 'Admission']
        );
    }

    private function report(string $msg): void
    {
        if ($this->command) {
            $this->command->info($msg);
        }
    }
}
