<?php

namespace Modules\MedEmergency\Http\Controllers;

use App\Contact;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Modules\MedEmergency\Entities\MderVisit;
use Modules\MedEmergency\Entities\MderVisitEvent;

/**
 * ER arrivals (SIFA P6-T3) — the front door. A minimal name + phone quick-reg
 * creates a visit immediately (patient_id / contact_id may stay null so triage
 * is never blocked), and OPTIONALLY links or quick-creates an ERP App\Contact +
 * a ClinicCore clc_patient — mirroring how ClcPatientController / the patient
 * contact controller create them. Guarded by mder.triage.
 */
class ArrivalController extends MedEmergencyBaseController
{
    /** Arrivals form. */
    public function create()
    {
        $this->guard('mder.triage');

        return view('medemergency::arrivals.create', [
            'arrivalModes' => MderVisit::ARRIVAL_MODES,
            'hasClinic'    => Schema::hasTable('clc_patients'),
        ]);
    }

    /**
     * Quick-register an arrival. name is required; phone optional. If link_patient
     * is on we resolve/create the contact + patient; otherwise the visit carries
     * only the denormalised patient_name so the board works without a full record.
     */
    public function store(Request $request)
    {
        $this->guard('mder.triage');

        $data = $this->validate($request, [
            'patient_name'   => 'required|string|max:191',
            'phone'          => 'nullable|string|max:40',
            'arrival_mode'   => 'nullable|string|in:' . implode(',', MderVisit::ARRIVAL_MODES),
            'chief_complaint' => 'nullable|string|max:2000',
            'link_patient'   => 'nullable|boolean',
        ]);

        $businessId = $this->businessId();

        $patientId = null;
        $contactId = null;

        // Optionally attach a real contact + clc patient (fail-soft on ClinicCore).
        if ($request->boolean('link_patient') && Schema::hasTable('clc_patients')) {
            [$contactId, $patientId] = $this->resolveOrCreatePatient($businessId, $data['patient_name'], $data['phone'] ?? null);
        }

        $visit = MderVisit::create([
            'business_id'     => $businessId,
            'visit_no'        => MderVisit::nextVisitNo($businessId),
            'patient_id'      => $patientId,
            'contact_id'      => $contactId,
            'patient_name'    => $data['patient_name'],
            'arrival_at'      => now(),
            'arrival_mode'    => $data['arrival_mode'] ?? 'walk_in',
            'chief_complaint' => $data['chief_complaint'] ?? null,
            'board_status'    => 'awaiting_triage',
            'created_by'      => auth()->id(),
        ]);

        MderVisitEvent::log($visit->id, 'arrived', 'Arrival — ' . str_replace('_', ' ', $visit->arrival_mode));

        return redirect()->route('mder.board.index')
            ->with('status', ['success' => 1, 'msg' => __('medemergency::lang.arrival_registered', ['no' => $visit->visit_no])]);
    }

    /**
     * Resolve an existing contact by phone (this business) or quick-create one,
     * then resolve / create the ClinicCore patient for that contact. Mirrors the
     * minimal Contact::create used by ClcPatientContactController and the
     * ClcPatient row shape used by ClcPatientController::store. Fail-soft — any
     * error leaves the visit unlinked rather than blocking the arrival.
     *
     * @return array{0: ?int, 1: ?int}  [contactId, patientId]
     */
    private function resolveOrCreatePatient(int $businessId, string $name, ?string $phone): array
    {
        try {
            $contact = null;
            if (! empty($phone)) {
                $contact = Contact::where('business_id', $businessId)
                    ->where('mobile', $phone)
                    ->first();
            }

            if (! $contact) {
                $contact = Contact::create([
                    'business_id'    => $businessId,
                    'name'           => $name,
                    'mobile'         => $phone,
                    'type'           => 'customer',
                    'contact_status' => 'active',
                    'created_by'     => auth()->id(),
                ]);
            }

            // Reuse the newest patient for this contact, else create a minimal one.
            $patient = DB::table('clc_patients')
                ->where('business_id', $businessId)
                ->where('contact_id', $contact->id)
                ->orderByDesc('id')
                ->first(['id']);

            $patientId = $patient->id ?? null;

            if (! $patientId) {
                $insert = [
                    'business_id'  => $businessId,
                    'contact_id'   => $contact->id,
                    'patient_name' => $name,
                    'status'       => 'active',
                    'created_at'   => now(),
                    'updated_at'   => now(),
                ];
                $patientId = (int) DB::table('clc_patients')->insertGetId($insert);

                // Ensure the ClinicCore owner-detail row exists (as the patient
                // controllers do) so downstream screens have their satellite.
                if (Schema::hasTable('clc_patient_contact_details')
                    && ! DB::table('clc_patient_contact_details')->where('contact_id', $contact->id)->exists()) {
                    DB::table('clc_patient_contact_details')->insert([
                        'business_id' => $businessId,
                        'contact_id'  => $contact->id,
                        'created_at'  => now(),
                        'updated_at'  => now(),
                    ]);
                }
            }

            return [(int) $contact->id, (int) $patientId];
        } catch (\Throwable $e) {
            \Log::warning('MedEmergency arrival patient link skipped: ' . $e->getMessage());

            return [null, null];
        }
    }
}
