<?php

namespace Modules\MedAccounting\Database\Seeders;

use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Modules\MedAccounting\Entities\MedaccAccount;

/**
 * Seeds a standard medical chart of accounts per business (is_system = true).
 * Idempotent (firstOrCreate keyed on business_id + code) and guarded to create the
 * tree only when the business has NO accounts yet, so re-runs / repair never
 * disturb a business that has already customised its COA.
 *
 * The codes here MUST match config('medaccounting.accounts') so AutoPostingService
 * can resolve every mapping.
 *
 * Structure (hierarchical codes):
 *   1000 Assets → 1100 Cash, 1110 Bank, 1200 AR, 1300 Inventory
 *   2000 Liabilities → 2100 AP, 2200 Tax Payable, 2300 Payroll Payable
 *   3000 Equity → 3100 Owner's Capital, 3200 Retained Earnings
 *   4000 Revenue → 4000 Patient Services, 4100 Consultation, 4200 Lab,
 *                  4300 Pharmacy, 4400 Imaging
 *   5000 Expense → 5100 Salaries, 5200 Medical Supplies (COGS), 5300 Utilities,
 *                  5900 General & Administrative
 */
class MedaccChartSeeder extends Seeder
{
    /**
     * Standard medical COA definition: [code, name, type, sub_type, parent_code].
     * Parents are listed before their children so parent_id resolves in one pass.
     *
     * @var array<int,array{0:string,1:string,2:string,3:?string,4:?string}>
     */
    private array $chart = [
        // Assets (1000s)
        ['1000', 'Assets', 'asset', null, null],
        ['1100', 'Cash on Hand', 'asset', 'current_asset', '1000'],
        ['1110', 'Bank Account', 'asset', 'current_asset', '1000'],
        ['1200', 'Accounts Receivable', 'asset', 'current_asset', '1000'],
        ['1300', 'Inventory — Medical Supplies', 'asset', 'current_asset', '1000'],

        // Liabilities (2000s)
        ['2000', 'Liabilities', 'liability', null, null],
        ['2100', 'Accounts Payable', 'liability', 'current_liability', '2000'],
        ['2200', 'Tax Payable', 'liability', 'current_liability', '2000'],
        ['2300', 'Payroll / Wages Payable', 'liability', 'current_liability', '2000'],

        // Equity (3000s)
        ['3000', 'Equity', 'equity', null, null],
        ['3100', "Owner's Capital", 'equity', null, '3000'],
        ['3200', 'Retained Earnings', 'equity', null, '3000'],

        // Revenue (4000s)
        ['4000', 'Patient Services Revenue', 'revenue', 'operating_revenue', null],
        ['4100', 'Consultation Revenue', 'revenue', 'operating_revenue', '4000'],
        ['4200', 'Laboratory Revenue', 'revenue', 'operating_revenue', '4000'],
        ['4300', 'Pharmacy Revenue', 'revenue', 'operating_revenue', '4000'],
        ['4400', 'Imaging Revenue', 'revenue', 'operating_revenue', '4000'],

        // Expenses (5000s)
        ['5000', 'Expenses', 'expense', null, null],
        ['5100', 'Salaries & Wages Expense', 'expense', 'operating_expense', '5000'],
        ['5200', 'Cost of Medical Supplies', 'expense', 'cost_of_sales', '5000'],
        ['5300', 'Utilities Expense', 'expense', 'operating_expense', '5000'],
        ['5900', 'General & Administrative Expense', 'expense', 'operating_expense', '5000'],
    ];

    public function run(?int $onlyBusinessId = null): void
    {
        if (! Schema::hasTable('medacc_accounts') || ! Schema::hasTable('business')) {
            return;
        }

        $businessIds = $onlyBusinessId
            ? [$onlyBusinessId]
            : DB::table('business')->pluck('id')->map(fn ($id) => (int) $id)->all();

        foreach ($businessIds as $businessId) {
            $this->seedForBusiness($businessId);
        }
    }

    /** Seed the standard chart for one business (only when it has none). */
    public function seedForBusiness(int $businessId): void
    {
        // Guard: only seed if the business has no accounts yet (so we never fight a
        // business that already customised its COA).
        $already = MedaccAccount::where('business_id', $businessId)->exists();
        if ($already) {
            return;
        }

        $codeToId = [];

        foreach ($this->chart as [$code, $name, $type, $subType, $parentCode]) {
            $account = MedaccAccount::firstOrCreate(
                ['business_id' => $businessId, 'code' => $code],
                [
                    'name'      => $name,
                    'type'      => $type,
                    'sub_type'  => $subType,
                    'parent_id' => $parentCode ? ($codeToId[$parentCode] ?? null) : null,
                    'is_active' => true,
                    'is_system' => true,
                ]
            );

            $codeToId[$code] = $account->id;
        }
    }
}
