<?php

namespace Modules\MedAccounting\Console;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Modules\MedAccounting\Entities\MedaccAccount;
use Modules\MedAccounting\Services\AutoPostingService;

/**
 * medacc:sync-postings {--since=} {--business=}
 *
 * Scans recent ERP events (sells, payments, purchases, expenses, payroll) and
 * posts any MISSING journal entries via AutoPostingService::backfill. Idempotent —
 * MedaccJournalEntry::existsForReference guards every post, so re-running never
 * double-posts. This is the batch half of auto-posting; the on-demand half is
 * AutoPostingService::post* called from application code / seeders.
 *
 * Fail-soft: a business with no seeded chart of accounts is skipped with a
 * warning; a bad event is logged and skipped. ClinicCore / ERP tables are guarded
 * with Schema::hasTable inside the service.
 */
class SyncPostingsCommand extends Command
{
    protected $signature = 'medacc:sync-postings
        {--since= : Y-m-d lower bound on transaction/payment date (default: no bound)}
        {--business= : limit to one business_id (default: every business with a chart of accounts)}';

    protected $description = 'Backfill MedAccounting journal entries from existing ERP events (idempotent).';

    public function handle(AutoPostingService $auto): int
    {
        if (! Schema::hasTable('medacc_accounts') || ! Schema::hasTable('transactions')) {
            $this->warn('MedAccounting or ERP tables missing — nothing to do.');

            return self::SUCCESS;
        }

        $since = $this->option('since') ?: null;

        $businessIds = $this->option('business')
            ? [(int) $this->option('business')]
            : MedaccAccount::query()->distinct()->pluck('business_id')->map(fn ($id) => (int) $id)->all();

        if (empty($businessIds)) {
            $this->warn('No business has a seeded chart of accounts yet — run the module seeder first.');

            return self::SUCCESS;
        }

        $grand = ['invoice' => 0, 'payment' => 0, 'purchase' => 0, 'expense' => 0, 'payroll' => 0];

        foreach ($businessIds as $businessId) {
            // Skip a business whose chart of accounts was never seeded.
            $hasChart = MedaccAccount::where('business_id', $businessId)->exists();
            if (! $hasChart) {
                $this->warn("business #{$businessId}: no chart of accounts — skipped.");
                continue;
            }

            try {
                $counts = $auto->backfill($businessId, $since);
            } catch (\Throwable $e) {
                \Log::warning("MedAccounting sync-postings failed for business #{$businessId}: " . $e->getMessage());
                $this->error("business #{$businessId}: " . $e->getMessage());
                continue;
            }

            foreach ($counts as $k => $v) {
                $grand[$k] += $v;
            }

            $this->info(sprintf(
                'business #%d: +%d invoice, +%d payment, +%d purchase, +%d expense, +%d payroll',
                $businessId, $counts['invoice'], $counts['payment'], $counts['purchase'], $counts['expense'], $counts['payroll']
            ));
        }

        $this->info(sprintf(
            'MedAccounting sync complete — posted %d journal entries (%d invoice, %d payment, %d purchase, %d expense, %d payroll).',
            array_sum($grand), $grand['invoice'], $grand['payment'], $grand['purchase'], $grand['expense'], $grand['payroll']
        ));

        return self::SUCCESS;
    }
}
