<?php

namespace App\Console\Commands;

use App\Models\Credit;
use App\Services\CreditStatusSyncService;
use App\Services\SmartCreditStateResolver;
use Carbon\Carbon;
use Illuminate\Console\Command;

class ReconcileCreditStatuses extends Command
{
    /**
     * Firma del comando:
     *
     *  php artisan credits:reconcile-status
     *  php artisan credits:reconcile-status --apply
     */
    protected $signature = 'credits:reconcile-status
        {--apply : Aplica los cambios en la base de datos (por defecto solo simula)}';

    protected $description = 'Reconcilia el campo status de los créditos usando SmartCreditStateResolver sin tocar pagos ni cuotas.';

    private const PREVIEW_LIMIT = 50;

    public function handle(SmartCreditStateResolver $resolver, CreditStatusSyncService $syncService): int
    {
        $apply = (bool) $this->option('apply');

        $this->info('==============================================');
        $this->info(' RECONCILIACIÓN DE ESTADOS DE CRÉDITOS');
        $this->info('==============================================');
        $this->line('Fecha de corte: '.Carbon::today()->toDateString());
        $this->line('Modo: '.($apply ? 'APLICANDO CAMBIOS' : 'SOLO LECTURA (dry-run)'));
        $this->newLine();

        $totalCredits = 0;
        $checkedCredits = 0;
        $mismatchCount = 0;
        $updatedCount = 0;
        $skippedLegacy = 0;
        $previewRows = [];

        // IMPORTANTE: Excluimos créditos padre (que tienen hijos derivados).
        // Eager load de 'installments' y 'children': habilita el modo batch de
        // SmartCreditStateResolver sin N+1 queries (isParent() relation-aware).
        Credit::with(['installments', 'children'])
            ->whereDoesntHave('children')
            ->orderBy('id')
            ->chunkById(200, function ($credits) use (
                $resolver,
                $syncService,
                $apply,
                &$totalCredits,
                &$checkedCredits,
                &$mismatchCount,
                &$updatedCount,
                &$skippedLegacy,
                &$previewRows
            ) {
                // Resolver todos los estados del chunk en una sola pasada batch
                $expectedStatuses = $resolver->resolveMany($credits);

                /** @var Credit $credit */
                foreach ($credits as $credit) {
                    $totalCredits++;

                    // 1) Saltar estados legacy cerrados para no tocar históricos especiales
                    if (in_array($credit->status, Credit::CLOSED_STATES, true)
                        && ! in_array($credit->status, [
                            Credit::STATUS_ACTIVE,
                            Credit::STATUS_DELAYED,
                            Credit::STATUS_OVERDUE,
                            Credit::STATUS_PAID,
                            Credit::STATUS_CANCELED,
                        ], true)
                    ) {
                        $skippedLegacy++;

                        continue;
                    }

                    $checkedCredits++;

                    $expectedStatus = $expectedStatuses[$credit->id];
                    $currentStatus = $credit->status;

                    if ($expectedStatus !== $currentStatus) {
                        $mismatchCount++;

                        // Guardar algunos ejemplos para mostrar en tabla
                        if (count($previewRows) < self::PREVIEW_LIMIT) {
                            $previewRows[] = [
                                'id' => $credit->id,
                                'company_id' => $credit->company_id,
                                'current_status' => $currentStatus,
                                'expected' => $expectedStatus,
                                'due_date' => optional($credit->due_date)->toDateString(),
                                'remaining' => number_format($credit->remaining_balance, 2, ',', '.'),
                            ];
                        }

                        if ($apply) {
                            $syncService->forceSync($credit);
                            $updatedCount++;
                        }
                    }
                }
            });

        // RESUMEN
        $this->newLine();
        $this->info('Resumen de la reconciliación');
        $this->line('----------------------------------------------');
        $this->line('Créditos totales          : '.$totalCredits);
        $this->line('Créditos revisados        : '.$checkedCredits);
        $this->line('Créditos con discrepancia : '.$mismatchCount);
        $this->line('Créditos legacy omitidos  : '.$skippedLegacy);

        if ($apply) {
            $this->line('Créditos ACTUALIZADOS     : '.$updatedCount);
        }

        // Mostrar ejemplos de discrepancias
        if (! empty($previewRows)) {
            $this->newLine();
            $this->info('Ejemplos de créditos con status inconsistente:');
            $this->table(
                ['ID', 'Company', 'Status actual', 'Status esperado', 'Due date', 'Saldo pendiente'],
                $previewRows
            );
        } else {
            $this->newLine();
            $this->info('✅ No se encontraron discrepancias de estado.');
        }

        $this->newLine();
        if ($apply) {
            $this->info('✅ Reconciliación aplicada correctamente.');
        } else {
            $this->comment('💡 Modo simulación. Para aplicar los cambios:');
            $this->comment('   php artisan credits:reconcile-status --apply');
        }

        return self::SUCCESS;
    }
}
