<?php

namespace Modules\MedBilling\Database\Seeders;

use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Modules\MedBilling\Entities\MedbillChargeItem;
use Modules\MedBilling\Entities\MedbillClaim;
use Modules\MedBilling\Entities\MedbillClaimItem;
use Modules\MedBilling\Entities\MedbillPatientPolicy;
use Modules\MedBilling\Entities\MedbillPayer;

/**
 * Demo data for the business named 'Shifa One' only (skips silently elsewhere).
 * Uses EXISTING demo data — never invents patients/appointments/products.
 *
 * Seeds:
 *   - 2 payers: one insurance (linked to a selling_price_group if the business
 *     has one) + one corporate.
 *   - policies for up to 2 existing clc_patients, linking a Wave-A
 *     clc_patient_insurances card row where one exists for that patient.
 *   - one captured + billed charge with a claim moved to `submitted`.
 *
 * Everything is idempotent (firstOrCreate keyed on natural columns) so repair /
 * re-runs never duplicate. All ERP integration is fail-soft.
 */
class MedbillDemoSeeder extends Seeder
{
    public function run(): void
    {
        if (! Schema::hasTable('business') || ! Schema::hasTable('medbill_payers')) {
            return;
        }

        $business = DB::table('business')->where('name', 'Shifa One')->first();
        if (empty($business)) {
            return; // not the Shifa host / demo DB — skip silently
        }

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

        // ── Payers ──────────────────────────────────────────────────────────
        $priceGroupId = Schema::hasTable('selling_price_groups')
            ? DB::table('selling_price_groups')->where('business_id', $businessId)->where('is_active', 1)->orderBy('id')->value('id')
            : null;

        $insurer = MedbillPayer::firstOrCreate(
            ['business_id' => $businessId, 'code' => 'INS-DEMO'],
            [
                'name'                      => 'Demo Health Insurance',
                'payer_type'                => 'insurance',
                'default_price_group_id'    => $priceGroupId ? (int) $priceGroupId : null,
                'claim_submission'          => 'portal',
                'pre_auth_required_default' => true,
                'settlement_terms_days'     => 30,
                'is_active'                 => true,
                'contact'                   => ['email' => 'claims@demo-insure.test'],
            ]
        );

        $corporate = MedbillPayer::firstOrCreate(
            ['business_id' => $businessId, 'code' => 'CORP-DEMO'],
            [
                'name'                  => 'Demo Corporate Account',
                'payer_type'            => 'corporate',
                'claim_submission'      => 'email',
                'settlement_terms_days' => 45,
                'is_active'             => true,
            ]
        );

        // ── Policies for up to 2 existing patients ─────────────────────────
        if (! Schema::hasTable('clc_patients')) {
            $this->report('MedBilling demo: payers seeded (ClinicCore absent — no policies/claim).');

            return;
        }

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

        if ($patients->isEmpty()) {
            $this->report('MedBilling demo: payers seeded (no patients — no policies/claim).');

            return;
        }

        $payerCycle = [$insurer, $corporate];
        $policies = [];

        foreach ($patients as $i => $patient) {
            $payer = $payerCycle[$i % 2];

            // Link a Wave-A insurance card if one exists for this patient.
            $cardId = Schema::hasTable('clc_patient_insurances')
                ? DB::table('clc_patient_insurances')
                    ->where('business_id', $businessId)
                    ->where('patient_id', $patient->id)
                    ->orderByDesc('id')
                    ->value('id')
                : null;

            $policy = MedbillPatientPolicy::firstOrCreate(
                [
                    'business_id'   => $businessId,
                    'payer_id'      => $payer->id,
                    'patient_id'    => $patient->id,
                    'policy_number' => 'POL-' . $businessId . '-' . $patient->id,
                ],
                [
                    'clc_patient_insurance_id' => $cardId ? (int) $cardId : null,
                    'contact_id'               => (int) $patient->contact_id,
                    'plan_name'                => $payer->payer_type === 'insurance' ? 'Standard Plan' : 'Corporate Cover',
                    'coverage_pct'             => 80,
                    'copay_fixed'              => 10,
                    'status'                   => 'active',
                ]
            );

            $policies[$patient->id] = $policy;
        }

        // ── One captured + billed charge with a submitted claim ────────────
        // Use the first patient that has an active policy. Do NOT create an ERP
        // sell here (demo must not mutate ERP invoicing / stock); instead we stage
        // a billed charge + a submitted claim referencing an existing appointment's
        // erp_sell_id when one is present, else leave transaction_id null.
        $firstPatient = $patients->first();
        $policy = $policies[$firstPatient->id] ?? null;

        if ($policy) {
            $appt = Schema::hasTable('clc_appointments')
                ? DB::table('clc_appointments')
                    ->where('business_id', $businessId)
                    ->where('patient_id', $firstPatient->id)
                    ->orderByDesc('id')
                    ->first(['id', 'erp_sell_id'])
                : null;

            $appointmentId = $appt->id ?? null;
            $erpSellId = $appt->erp_sell_id ?? null;

            $charge = MedbillChargeItem::firstOrCreate(
                [
                    'business_id' => $businessId,
                    'source_type' => 'manual',
                    'source_id'   => $appointmentId,
                    'patient_id'  => $firstPatient->id,
                    'description' => 'Consultation (demo)',
                ],
                [
                    'appointment_id' => $appointmentId,
                    'qty'            => 1,
                    'unit_price'     => 100,
                    'status'         => 'billed',
                    'transaction_id' => $erpSellId ? (int) $erpSellId : null,
                ]
            );

            $claim = MedbillClaim::firstOrCreate(
                [
                    'business_id'    => $businessId,
                    'policy_id'      => $policy->id,
                    'transaction_id' => $erpSellId ? (int) $erpSellId : null,
                    'patient_id'     => $firstPatient->id,
                ],
                [
                    'claim_no'      => MedbillClaim::nextClaimNo($businessId),
                    'payer_id'      => $policy->payer_id,
                    'total_claimed' => 100,
                    'patient_share' => $policy->splitAmount(100)['patient_share'],
                    'payer_share'   => $policy->splitAmount(100)['payer_share'],
                    'status'        => 'submitted',
                    'submitted_at'  => now(),
                ]
            );

            MedbillClaimItem::firstOrCreate(
                ['claim_id' => $claim->id, 'charge_item_id' => $charge->id],
                ['description' => $charge->description, 'claimed_amount' => 100]
            );
        }

        $this->report('MedBilling demo: 2 payers, ' . count($policies) . ' policy(ies) and 1 submitted claim seeded for "Shifa One".');
    }

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