<?php

namespace Modules\MedPortal\Support;

use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;

/**
 * ClinicBridge — fail-soft read-only helpers over ClinicCore / ERP core tables.
 *
 * MedPortal binds to ClinicCore but must never hard-depend on it at runtime:
 * every accessor here checks Schema::hasTable first and returns an empty
 * collection / null when ClinicCore is absent, so the staff UI degrades
 * gracefully instead of erroring (spec HARD RULE: fail-soft cross-module).
 *
 * All queries are business_id-scoped. Nothing here writes.
 */
class ClinicBridge
{
    public static function hasClinic(): bool
    {
        return Schema::hasTable('clc_patients');
    }

    /**
     * Patient id => display name, business-scoped. Name = clc_patients.patient_name
     * else the linked ERP contact name.
     *
     * @return array<int,string>
     */
    public static function patientNames(int $businessId, ?array $patientIds = null): array
    {
        if (! self::hasClinic()) {
            return [];
        }

        $q = DB::table('clc_patients')
            ->where('clc_patients.business_id', $businessId);

        if ($patientIds !== null) {
            if (empty($patientIds)) {
                return [];
            }
            $q->whereIn('clc_patients.id', $patientIds);
        }

        if (Schema::hasTable('contacts')) {
            $q->leftJoin('contacts', 'contacts.id', '=', 'clc_patients.contact_id')
                ->select('clc_patients.id', 'clc_patients.patient_name', 'contacts.name as contact_name');
        } else {
            $q->select('clc_patients.id', 'clc_patients.patient_name', DB::raw('NULL as contact_name'));
        }

        return $q->get()->mapWithKeys(function ($r) {
            $name = $r->patient_name ?: ($r->contact_name ?: ('Patient #' . $r->id));

            return [(int) $r->id => $name];
        })->all();
    }

    /** A single patient's display name (or a "#id" fallback). */
    public static function patientName(int $businessId, int $patientId): string
    {
        return self::patientNames($businessId, [$patientId])[$patientId] ?? ('Patient #' . $patientId);
    }

    /**
     * Business patients for a <select>: [id => name]. Capped for the picker.
     *
     * @return array<int,string>
     */
    public static function patientOptions(int $businessId, int $limit = 500): array
    {
        if (! self::hasClinic()) {
            return [];
        }

        $ids = DB::table('clc_patients')
            ->where('business_id', $businessId)
            ->orderByDesc('id')
            ->limit($limit)
            ->pluck('id')
            ->map(fn ($id) => (int) $id)
            ->all();

        $names = self::patientNames($businessId, $ids);

        // Preserve the id ordering.
        $out = [];
        foreach ($ids as $id) {
            $out[$id] = $names[$id] ?? ('Patient #' . $id);
        }

        return $out;
    }

    /** contacts.id for a patient (the portal account holder), or null. */
    public static function contactIdForPatient(int $businessId, int $patientId): ?int
    {
        if (! self::hasClinic()) {
            return null;
        }

        $val = DB::table('clc_patients')
            ->where('business_id', $businessId)
            ->where('id', $patientId)
            ->value('contact_id');

        return $val ? (int) $val : null;
    }

    /** Business contacts (customers) for the guardian picker: [id => name]. */
    public static function contactOptions(int $businessId, int $limit = 500): array
    {
        if (! Schema::hasTable('contacts')) {
            return [];
        }

        return DB::table('contacts')
            ->where('business_id', $businessId)
            ->whereIn('type', ['customer', 'both'])
            ->orderBy('name')
            ->limit($limit)
            ->pluck('name', 'id')
            ->map(fn ($n) => (string) $n)
            ->all();
    }

    /** Doctor id => name, business-scoped. */
    public static function doctorNames(int $businessId): array
    {
        if (! Schema::hasTable('clc_doctors')) {
            return [];
        }

        return DB::table('clc_doctors')
            ->where('business_id', $businessId)
            ->pluck('name', 'id')
            ->map(fn ($n) => (string) $n)
            ->all();
    }

    public static function patientCount(int $businessId): int
    {
        if (! self::hasClinic()) {
            return 0;
        }

        return (int) DB::table('clc_patients')->where('business_id', $businessId)->count();
    }
}
