<?php

namespace Modules\MedPortal\Database\Seeders;

use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Modules\MedPortal\Entities\MportalDependent;
use Modules\MedPortal\Entities\MportalHealthLog;
use Modules\MedPortal\Entities\MportalPaymentIntent;
use Modules\MedPortal\Entities\MportalQuestionnaire;
use Modules\MedPortal\Entities\MportalQuestionnaireResponse;
use Modules\MedPortal\Entities\MportalRecordRelease;
use Modules\MedPortal\Entities\MportalShareGrant;
use Modules\MedPortal\Entities\MportalTelemedicine;
use Modules\MedPortal\Services\MessagingService;
use Modules\MedPortal\Services\QuestionnaireService;

/**
 * Demo data for the business named 'Shifa One' only (WARN — not silent —
 * elsewhere). Uses EXISTING ClinicCore demo data (patients / appointments) —
 * never invents them. Everything is idempotent (firstOrCreate / firstOrNew keyed
 * on natural columns) so repair / re-runs never duplicate. All cross-module
 * reads are fail-soft.
 *
 * Seeds for "Shifa One":
 *   - 1–2 dependents linking existing patients to their guardian contact
 *   - a few record releases (clinical_note released for one patient)
 *   - 2 message threads (one from patient, one staff reply)
 *   - a PHQ-9 response with a MODERATE score
 *   - health logs: a weight series + a BP series
 *   - 1 telemedicine link (STUB placeholder)
 *   - 1 payment intent (STUB, pending)
 *   - 1 share grant (temporary provider share)
 */
class MedportalDemoSeeder extends Seeder
{
    public function run(): void
    {
        if (! Schema::hasTable('business')) {
            $this->warn('MedPortal demo: `business` table missing — skipped.');

            return;
        }

        $business = DB::table('business')->where('name', 'Shifa One')->first();
        if (empty($business)) {
            $this->warn('MedPortal demo: business "Shifa One" not found — this is not the Shifa demo host, skipping demo data.');

            return;
        }

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

        if (! Schema::hasTable('clc_patients')) {
            $this->warn('MedPortal demo: ClinicCore (clc_patients) absent — cannot seed portal demo data.');

            return;
        }

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

        if ($patients->isEmpty()) {
            $this->warn('MedPortal demo: no patients for "Shifa One" — nothing to seed.');

            return;
        }

        $p1 = $patients[0];
        $p2 = $patients[1] ?? $patients[0];

        // ── Dependents: link each patient to its own guardian contact ────────
        $depCount = 0;
        foreach ([$p1, $p2] as $p) {
            if (empty($p->contact_id)) {
                continue;
            }
            MportalDependent::firstOrCreate(
                [
                    'business_id'          => $businessId,
                    'guardian_contact_id'  => (int) $p->contact_id,
                    'dependent_patient_id' => (int) $p->id,
                ],
                [
                    'relationship'     => $p->id === $p1->id ? 'child' : 'spouse',
                    'can_book'         => true,
                    'can_view_records' => true,
                ]
            );
            $depCount++;
        }

        // ── Record releases: release clinical notes for patient 1 ────────────
        MportalRecordRelease::firstOrNew([
            'business_id' => $businessId,
            'patient_id'  => (int) $p1->id,
            'record_type' => 'clinical_note',
        ])->fill([
            'released'    => true,
            'released_at' => now(),
            'notes'       => 'Demo: notes released to portal.',
        ])->save();

        // Explicitly hide vitals for patient 2 (demo of an override off-default).
        MportalRecordRelease::firstOrNew([
            'business_id' => $businessId,
            'patient_id'  => (int) $p2->id,
            'record_type' => 'vitals',
        ])->fill([
            'released' => false,
            'notes'    => 'Demo: vitals withheld pending review.',
        ])->save();

        // ── Messaging: 2 threads (idempotent by a marker in the body) ────────
        $messaging = app(MessagingService::class);
        $this->seedThread($messaging, $businessId, $p1, 'patient', 'Hello, I have a question about my prescription. [demo1]');
        $this->seedThread($messaging, $businessId, $p2, 'staff', 'Your recent lab results look good. Please book a follow-up. [demo2]');

        // ── PHQ-9 response with a MODERATE score ─────────────────────────────
        $this->seedPhq9($businessId, $p1);

        // ── Health logs: weight + BP series ──────────────────────────────────
        $this->seedHealthSeries($businessId, (int) $p1->id);

        // ── Telemedicine link (STUB) on the patient's latest appointment ─────
        if (Schema::hasTable('clc_appointments')) {
            $appt = DB::table('clc_appointments')
                ->where('business_id', $businessId)
                ->where('patient_id', $p1->id)
                ->orderByDesc('id')
                ->first(['id']);

            if ($appt) {
                MportalTelemedicine::firstOrCreate(
                    ['business_id' => $businessId, 'appointment_id' => (int) $appt->id],
                    [
                        'join_url' => rtrim((string) config('medportal.telemedicine.placeholder_base'), '/') . '/demo-shifa-1',
                        'provider' => 'builtin',
                        'status'   => 'scheduled',
                    ]
                );
            }
        }

        // ── Payment intent (STUB, pending) ───────────────────────────────────
        MportalPaymentIntent::firstOrCreate(
            [
                'business_id' => $businessId,
                'patient_id'  => (int) $p1->id,
                'reference'   => 'DEMO-INTENT-1',
            ],
            [
                'amount' => 150.00,
                'status' => 'pending',
                'method' => 'online',
            ]
        );

        // ── Share grant (temporary provider share) ───────────────────────────
        MportalShareGrant::firstOrCreate(
            [
                'business_id' => $businessId,
                'patient_id'  => (int) $p1->id,
                'shared_with' => 'Dr. External (demo@referral.test)',
            ],
            [
                'scope'      => 'records',
                'token'      => MportalShareGrant::newToken(),
                'expires_at' => now()->addDays(14),
            ]
        );

        $this->info("MedPortal demo: {$depCount} dependent(s), 2 message threads, releases, a moderate PHQ-9, a health series, 1 telemedicine link, 1 payment intent and 1 share grant seeded for \"Shifa One\".");
    }

    /** Create a one-message thread if the marker body doesn't already exist. */
    private function seedThread(MessagingService $messaging, int $businessId, $patient, string $senderType, string $body): void
    {
        if (empty($patient->contact_id)) {
            return;
        }

        $exists = DB::table('mportal_messages')
            ->where('business_id', $businessId)
            ->where('body', $body)
            ->exists();

        if ($exists) {
            return;
        }

        $senderId = $senderType === 'patient'
            ? (int) $patient->contact_id
            : (int) (DB::table('users')->where('business_id', $businessId)->value('id') ?? $patient->contact_id);

        $messaging->send(
            $businessId,
            (int) $patient->id,
            (int) $patient->contact_id,
            $senderType,
            $senderId,
            $body
        );
    }

    /** A completed PHQ-9 answering to a moderate total (~12). */
    private function seedPhq9(int $businessId, $patient): void
    {
        $phq9 = MportalQuestionnaire::whereNull('business_id')->where('code', 'phq9')->first();
        if (! $phq9) {
            return;
        }

        $existing = MportalQuestionnaireResponse::where('business_id', $businessId)
            ->where('patient_id', $patient->id)
            ->where('questionnaire_id', $phq9->id)
            ->first();

        if ($existing && $existing->completed_at) {
            return;
        }

        $response = $existing ?: new MportalQuestionnaireResponse([
            'business_id'      => $businessId,
            'patient_id'       => (int) $patient->id,
            'questionnaire_id' => (int) $phq9->id,
        ]);
        if (! $existing) {
            $response->save();
        }

        // 9 items summing to 12 → "moderate" (band 10–14).
        $answers = [2, 2, 1, 2, 1, 1, 1, 1, 1];
        app(QuestionnaireService::class)->complete($response, $answers);
    }

    /** A weight series and a BP series over the last few weeks. */
    private function seedHealthSeries(int $businessId, int $patientId): void
    {
        $weights = [82.5, 82.0, 81.4, 81.1, 80.6];
        foreach ($weights as $i => $w) {
            $loggedAt = now()->subDays((count($weights) - $i) * 7);
            MportalHealthLog::firstOrCreate(
                [
                    'business_id' => $businessId,
                    'patient_id'  => $patientId,
                    'metric'      => 'weight',
                    'logged_at'   => $loggedAt->toDateTimeString(),
                ],
                ['value_num' => $w, 'source' => 'patient']
            );
        }

        $bps = ['128/84', '126/82', '124/80', '122/79', '120/78'];
        foreach ($bps as $i => $bp) {
            $loggedAt = now()->subDays((count($bps) - $i) * 7);
            MportalHealthLog::firstOrCreate(
                [
                    'business_id' => $businessId,
                    'patient_id'  => $patientId,
                    'metric'      => 'blood_pressure',
                    'logged_at'   => $loggedAt->toDateTimeString(),
                ],
                ['value_text' => $bp, 'source' => 'patient']
            );
        }
    }

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

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