<?php

namespace Modules\MedWard\Entities;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;

/**
 * An inpatient episode (SIFA P6-T2 + P6-T5 ICU fields). Lifecycle + bed occupancy
 * are enforced by Modules\MedWard\Services\AdmissionService.
 */
class MedwardAdmission extends Model
{
    protected $table = 'medward_admissions';

    protected $guarded = ['id'];

    protected $casts = [
        'appointment_id'     => 'integer',
        'admitting_doctor_id' => 'integer',
        'admitted_at'        => 'datetime',
        'expected_discharge' => 'date',
        'discharged_at'      => 'datetime',
        'followup_date'      => 'date',
        'is_icu'             => 'boolean',
        'apache_ii'          => 'integer',
        'sofa'               => 'integer',
        'ventilator'         => 'boolean',
    ];

    public const STATUSES = ['admitted', 'discharge_pending', 'discharged'];

    public const ADMISSION_TYPES = ['elective', 'emergency', 'transfer', 'maternity', 'observation'];

    public const ADMISSION_SOURCES = ['er', 'outpatient', 'external', 'referral', 'other'];

    public const DISCHARGE_TYPES = ['recovered', 'improved', 'transferred', 'absconded', 'expired', 'referred', 'other'];

    public const ICU_TYPES = ['medical', 'surgical', 'cardiac', 'neuro', 'pediatric', 'neonatal'];

    public function ward()
    {
        return $this->belongsTo(MedwardWard::class, 'ward_id');
    }

    public function bed()
    {
        return $this->belongsTo(MedwardBed::class, 'bed_id');
    }

    public function bedAssignments()
    {
        return $this->hasMany(MedwardBedAssignment::class, 'admission_id');
    }

    public function marEntries()
    {
        return $this->hasMany(MedwardMarEntry::class, 'admission_id');
    }

    public function fluidBalances()
    {
        return $this->hasMany(MedwardFluidBalance::class, 'admission_id');
    }

    public function flowsheets()
    {
        return $this->hasMany(MedwardIcuFlowsheet::class, 'admission_id');
    }

    public function scopeForBusiness($query, $businessId)
    {
        return $query->where('business_id', $businessId);
    }

    public function scopeActive($query)
    {
        return $query->whereIn('status', ['admitted', 'discharge_pending']);
    }

    public function scopeIcu($query)
    {
        return $query->where('is_icu', true);
    }

    public function isActive(): bool
    {
        return in_array($this->status, ['admitted', 'discharge_pending'], true);
    }

    /** Allocate the next admission reference: ADM-{biz}-{0000001}. */
    public static function nextAdmissionNo(int $businessId): string
    {
        return DB::transaction(function () use ($businessId) {
            $last = static::where('business_id', $businessId)
                ->lockForUpdate()->orderByDesc('id')->value('admission_no');
            $n = 1;
            if ($last && preg_match('/-(\d+)$/', $last, $m)) {
                $n = ((int) $m[1]) + 1;
            }

            return 'ADM-' . $businessId . '-' . str_pad((string) $n, 7, '0', STR_PAD_LEFT);
        });
    }
}
