<?php

namespace Modules\MedWard\Services;

use Carbon\Carbon;
use Modules\MedWard\Entities\MedwardAdmission;
use Modules\MedWard\Entities\MedwardIcuFlowsheet;

/**
 * IcuService (SIFA P6-T5) — records ICU flow-sheet rows.
 *
 * chart()
 *   Creates a flow-sheet row, auto-computing MAP = (sys + 2*dia)/3. When the row
 *   crosses the configured critical floors (MAP < map_min, SpO2 < spo2_min) it
 *   raises a ClinicCore MedicalAlertService `critical_value` alert — idempotent
 *   PER FLOW-SHEET ROW via a unique source_type/source_id (so re-saving the same
 *   row refreshes rather than duplicates the alert). All alert integration is
 *   fail-soft (Rule 6): a missing/erroring ClinicCore never blocks charting.
 */
class IcuService
{
    /**
     * Record a flow-sheet row for an ICU admission.
     *
     * @param  array  $data  recorded_at?, recorded_by?, gcs_total?, rass?, pupils?,
     *                       hr?, bp_sys?, bp_dia?, spo2?, rr?, temp?, fio2?, peep?,
     *                       tidal_volume?, vasoactives?, drains?, interventions?,
     *                       labs_note?
     */
    public function chart(MedwardAdmission $admission, array $data): MedwardIcuFlowsheet
    {
        $businessId = (int) $admission->business_id;

        $map = MedwardIcuFlowsheet::computeMap($data['bp_sys'] ?? null, $data['bp_dia'] ?? null);

        $flowsheet = MedwardIcuFlowsheet::create([
            'business_id'   => $businessId,
            'admission_id'  => $admission->id,
            'recorded_at'   => $data['recorded_at'] ?? Carbon::now(),
            'recorded_by'   => $data['recorded_by'] ?? (auth()->check() ? (int) auth()->id() : null),
            'gcs_total'     => $data['gcs_total'] ?? null,
            'rass'          => $data['rass'] ?? null,
            'pupils'        => $data['pupils'] ?? null,
            'hr'            => $data['hr'] ?? null,
            'bp_sys'        => $data['bp_sys'] ?? null,
            'bp_dia'        => $data['bp_dia'] ?? null,
            'map_calc'      => $map,
            'spo2'          => $data['spo2'] ?? null,
            'rr'            => $data['rr'] ?? null,
            'temp'          => $data['temp'] ?? null,
            'fio2'          => $data['fio2'] ?? null,
            'peep'          => $data['peep'] ?? null,
            'tidal_volume'  => $data['tidal_volume'] ?? null,
            'vasoactives'   => $this->cleanRepeater($data['vasoactives'] ?? null),
            'drains'        => $this->cleanRepeater($data['drains'] ?? null),
            'interventions' => $data['interventions'] ?? null,
            'labs_note'     => $data['labs_note'] ?? null,
        ]);

        $this->raiseCriticalValues($admission, $flowsheet);

        return $flowsheet->fresh();
    }

    // ── internals ────────────────────────────────────────────────────────

    /**
     * Raise an idempotent critical_value alert when MAP / SpO2 breach the floors.
     * Fail-soft: no-op if ClinicCore's MedicalAlertService is unavailable.
     */
    protected function raiseCriticalValues(MedwardAdmission $admission, MedwardIcuFlowsheet $flowsheet): void
    {
        try {
            $svcClass = \Modules\ClinicCore\Entities\Services\MedicalAlertService::class;
            if (! class_exists($svcClass)) {
                return;
            }

            $breaches = [];
            $mapMin = (float) config('medward.icu_critical.map_min', 60);
            $spo2Min = (float) config('medward.icu_critical.spo2_min', 90);

            if ($flowsheet->map_calc !== null && (float) $flowsheet->map_calc < $mapMin) {
                $breaches[] = 'MAP ' . round((float) $flowsheet->map_calc, 1) . ' < ' . $mapMin;
            }
            if ($flowsheet->spo2 !== null && (float) $flowsheet->spo2 < $spo2Min) {
                $breaches[] = 'SpO2 ' . round((float) $flowsheet->spo2, 1) . '% < ' . $spo2Min . '%';
            }

            if (empty($breaches)) {
                return;
            }

            app($svcClass)->raise([
                'business_id' => (int) $admission->business_id,
                'patient_id'  => (int) $admission->patient_id,
                'alert_type'  => 'critical_value',
                'severity'    => 'critical',
                'title'       => __('medward::lang.icu_critical_value'),
                'details'     => implode('; ', $breaches),
                // Idempotent PER FLOW-SHEET ROW: same source key ⇒ refresh, not duplicate.
                'source_type' => 'medward_icu_flowsheets',
                'source_id'   => (int) $flowsheet->id,
                'created_by'  => $flowsheet->recorded_by,
            ]);
        } catch (\Throwable $e) {
            \Log::warning('MedWard ICU critical-value alert skipped: ' . $e->getMessage());
        }
    }

    /**
     * Normalise a repeater payload (vasoactives / drains) to a clean list of
     * non-empty associative rows, or null when nothing was entered.
     */
    protected function cleanRepeater($rows): ?array
    {
        if (! is_array($rows)) {
            return null;
        }

        $clean = [];
        foreach ($rows as $row) {
            if (! is_array($row)) {
                continue;
            }
            $filtered = array_filter($row, fn ($v) => $v !== null && trim((string) $v) !== '');
            if (! empty($filtered)) {
                $clean[] = $filtered;
            }
        }

        return ! empty($clean) ? array_values($clean) : null;
    }
}
