<?php

declare(strict_types=1);

namespace App\Filament\Resources\Credits\Actions;

use App\Enums\CreditAuditEvent;
use App\Models\Credit;
use App\Services\CreditOperationService;
use Filament\Actions\Action;
use Filament\Forms;
use Filament\Notifications\Notification;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\HtmlString;

/**
 * Retira un crédito de la cartera operativa sin decidir aún si se cierra.
 *
 * Para qué sirve: hay créditos cuyo desenlace todavía no está claro y que
 * mientras tanto ensucian la ruta del cobrador. Archivar los esconde.
 *
 * Qué NO hace: no toca un solo registro financiero. No borra el desembolso, no
 * condona nada, no reescribe cuotas. Solo cambia el estado.
 *
 * Qué implica, y por eso la confirmación lo dice con el número delante:
 * `archived` pertenece a `CLOSED_STATES`, así que el saldo sale de "por cobrar"
 * y el patrimonio del panel baja en esa cantidad. Tampoco se le pueden
 * registrar pagos hasta desarchivarlo.
 *
 * La plata sigue debiéndose: `credify:verify-equity` sigue contando el capital
 * de los créditos archivados, porque para la contabilidad son un activo — lo
 * que cambia es que dejan de ser cartera operativa.
 */
class ArchiveCreditAction
{
    public static function make(): Action
    {
        return Action::make('archive_credit')
            ->label('Archivar crédito')
            ->icon('heroicon-o-archive-box')
            ->color('gray')
            ->requiresConfirmation()
            ->modalIcon('heroicon-o-archive-box')
            ->modalHeading('Archivar crédito')
            ->modalDescription(fn (Credit $record) => new HtmlString(self::descripcion($record)))
            ->modalSubmitActionLabel('Archivar')
            ->visible(fn (?Credit $record): bool => filled($record) && Gate::allows('archive', $record))
            ->schema([
                Forms\Components\Textarea::make('reason')
                    ->label('¿Por qué se archiva?')
                    ->helperText('Queda en la bitácora del crédito. Útil cuando alguien pregunte dentro de tres meses.')
                    ->required()
                    ->maxLength(500),
            ])
            ->action(function (array $data, Credit $credit): void {
                Gate::authorize('archive', $credit);

                $saldo = self::saldoPendiente($credit);

                $credit->update(['status' => Credit::STATUS_ARCHIVED]);

                app(CreditOperationService::class)->audit(
                    creditId: $credit->id,
                    action: CreditAuditEvent::CREDIT_ARCHIVED,
                    data: [
                        'reason' => $data['reason'] ?? null,
                        'saldo_retirado_de_cartera' => $saldo,
                    ],
                );

                Notification::make()
                    ->title('Crédito archivado')
                    ->success()
                    ->body(
                        'El cobrador ya no lo ve. Salieron $'.number_format($saldo, 0, ',', '.').
                        ' de la cartera; se pueden devolver desarchivándolo.'
                    )
                    ->send();
            });
    }

    /** Lo que falta por cobrar: es exactamente lo que sale de la cartera. */
    private static function saldoPendiente(Credit $credit): float
    {
        // Se suma en SQL y no hidratando las cuotas: es una sola consulta y el
        // modal lo pide dos veces (descripción y acción).
        return (float) $credit->installments()
            ->whereIn('status', ['pending', 'partial_paid', 'overdue'])
            ->sum(DB::raw('GREATEST(0, total_amount - amount_paid)'));
    }

    private static function descripcion(Credit $credit): string
    {
        $saldo = number_format(self::saldoPendiente($credit), 0, ',', '.');

        return <<<HTML
            <p class="mb-3">El cobrador dejará de ver este crédito y no se le podrán registrar pagos.</p>
            <p class="mb-3">
                <strong>Salen \${$saldo} de la cartera</strong>, y el patrimonio del panel baja en esa cantidad.
                La deuda sigue existiendo: no se condona ni se borra nada.
            </p>
            <p class="text-sm opacity-75">Se puede desarchivar en cualquier momento y todo vuelve a su sitio.</p>
        HTML;
    }
}
