<?php

declare(strict_types=1);

namespace App\Filament\Resources\Credits\Actions;

use App\DTOs\ExtendWithInterestData;
use App\Enums\Periodicity;
use App\Exceptions\CreditOperationException;
use App\Filament\Resources\Credits\CreditResource;
use App\Models\Credit;
use App\Models\Installment;
use App\Services\CreditManager;
use App\Services\Credits\CreditOperationOrchestrator;
use App\Support\CreditRules;
use Carbon\Carbon;
use Filament\Actions\Action;
use Filament\Forms\Components\DatePicker;
use Filament\Forms\Components\Placeholder;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Notifications\Notification;
use Filament\Schemas\Components\Section;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\HtmlString;
use Illuminate\Support\Str;

/**
 * Acción de Filament para EXTENDER un crédito CON INTERESES ADICIONALES.
 *
 * DIFERENCIA CON EXTENSIÓN SIMPLE:
 * - ExtendCreditAction: NO permite créditos con pagos de capital
 * - Esta acción: SÍ PERMITE créditos con pagos de capital (prórroga con réditos)
 *
 * CASO DE USO REAL (Credit #53 - Yulisa Rodriguez):
 * - Capital: 500,000, Total: 700,000 (10 cuotas × 70,000)
 * - Pagado: 6 cuotas = 420,000
 * - Pendiente: 280,000
 * - Solicita: +1 mes de intereses adicionales
 *
 * Esta acción está específicamente diseñada para este escenario de negocio.
 */
class ExtendWithInterestAction
{
    public static function make(): Action
    {
        return Action::make('extend_with_interest')
            ->label('Prorrogar con Réditos')
            ->icon('heroicon-o-calendar-days')
            ->color('warning')
            ->modalHeading('Prorrogar Crédito con Intereses Adicionales')
            ->modalDescription(fn (Credit $record): string => self::getModalDescription($record)
            )
            ->modalSubmitActionLabel('Prorrogar Crédito')
            ->modalWidth('xl')
            ->visible(fn (?Credit $record): bool => filled($record) && app(CreditOperationOrchestrator::class)->canExtendWithInterest($record)
            )
            ->schema(fn (Credit $record): array => self::getFormSchema($record))
            ->action(function (array $data, Credit $record) {
                self::executeAction($data, $record);
            });
    }

    /**
     * Genera la descripción del modal con información contextual.
     */
    private static function getModalDescription(Credit $record): string
    {
        $manager = app(CreditManager::class);
        $remaining = $manager->getRemainingBalance($record);
        $hasCapitalPayments = CreditRules::hasCapitalPayments($record);

        $description = sprintf(
            'Extiende el plazo del crédito aplicando intereses adicionales sobre el saldo pendiente (%s).',
            '$ '.number_format($remaining, 2, ',', '.')
        );

        if ($hasCapitalPayments) {
            $description .= "\n\nEste crédito tiene cuotas pagadas. Se preservarán todos los pagos históricos.";
        }

        return $description;
    }

    /**
     * Define el esquema del formulario.
     */
    private static function getFormSchema(Credit $record): array
    {
        $manager = app(CreditManager::class);
        $remaining = $manager->getRemainingBalance($record);
        $paidCount = $record->installments()->where('status', Installment::STATUS_PAID)->count();
        $pendingCount = $record->installments()->where('status', '!=', Installment::STATUS_PAID)->count();

        return [
            // Sección: Estado actual del crédito
            Section::make('Estado Actual del Crédito')
                ->description('Información del crédito antes de la prórroga')
                ->schema([
                    Placeholder::make('credit_id')
                        ->label('Código del Crédito')
                        ->content(fn () => "#{$record->code}"),

                    Placeholder::make('current_balance')
                        ->label('Saldo Pendiente')
                        ->content(fn () => '$ '.number_format($remaining, 2, ',', '.')),

                    Placeholder::make('paid_installments')
                        ->label('Cuotas Pagadas')
                        ->content(fn () => "{$paidCount} de {$record->installments_count}"),

                    Placeholder::make('pending_installments')
                        ->label('Cuotas Pendientes')
                        ->content(fn () => $pendingCount),

                    Placeholder::make('current_rate')
                        ->label('Tasa Actual')
                        ->content(fn () => $record->interest_rate.'%'),

                    Placeholder::make('current_status')
                        ->label('Estado')
                        ->content(fn () => $record->getStatusLabel()),
                ])
                ->columns(3),

            // Sección: Configuración de intereses adicionales
            Section::make('Intereses Adicionales (Réditos)')
                ->description('Configure los intereses a aplicar sobre el saldo pendiente')
                ->schema([
                    TextInput::make('additional_interest_periods')
                        ->label('Períodos de interés adicional')
                        ->numeric()
                        ->minValue(0)
                        ->maxValue(12)
                        ->default(1)
                        ->required()
                        ->live(onBlur: true)
                        ->helperText('Número de meses/períodos de interés a agregar al saldo'),

                    TextInput::make('new_interest_rate')
                        ->label('Tasa de interés (%)')
                        ->numeric()
                        ->minValue(0)
                        ->maxValue(100)
                        ->step(0.01)
                        ->default($record->interest_rate)
                        ->suffix('%')
                        ->live(onBlur: true)
                        ->helperText('Puede mantener la tasa original o ajustarla'),

                    Placeholder::make('calculated_interest')
                        ->label('Interés adicional calculado')
                        ->content(function ($get) use ($remaining, $record) {
                            $periods = (int) ($get('additional_interest_periods') ?? 1);
                            $rate = (float) ($get('new_interest_rate') ?? $record->interest_rate);
                            $interest = $remaining * ($rate / 100) * $periods;

                            return '$ '.number_format($interest, 2, ',', '.');
                        }),

                    Placeholder::make('new_total')
                        ->label('Nuevo total a pagar')
                        ->content(function ($get) use ($remaining, $record) {
                            $periods = (int) ($get('additional_interest_periods') ?? 1);
                            $rate = (float) ($get('new_interest_rate') ?? $record->interest_rate);
                            $interest = $remaining * ($rate / 100) * $periods;
                            $total = $remaining + $interest;

                            return '$ '.number_format($total, 2, ',', '.');
                        }),
                ])
                ->columns(2),

            // Sección: Configuración del nuevo plan de pagos
            Section::make('Nuevo Plan de Pagos')
                ->description('Configure las cuotas del nuevo crédito')
                ->schema([
                    TextInput::make('new_installments')
                        ->label('Número de nuevas cuotas')
                        ->numeric()
                        ->minValue(1)
                        ->maxValue(52)
                        ->default(fn () => max(4, $record->installments_count))
                        ->required()
                        ->live(onBlur: true)
                        ->helperText('Total de cuotas para el nuevo crédito'),

                    Placeholder::make('estimated_installment')
                        ->label('Cuota estimada')
                        ->content(function ($get) use ($remaining, $record) {
                            $periods = (int) ($get('additional_interest_periods') ?? 1);
                            $rate = (float) ($get('new_interest_rate') ?? $record->interest_rate);
                            $installments = (int) ($get('new_installments') ?? $record->installments_count);

                            if ($installments <= 0) {
                                return 'N/A';
                            }

                            $interest = $remaining * ($rate / 100) * $periods;
                            $total = $remaining + $interest;

                            // El nuevo crédito aplicará su propia tasa, así que la cuota real puede variar
                            // Esta es solo una estimación
                            $estimated = $total / $installments;

                            return '≈ $ '.number_format($estimated, 2, ',', '.').' (estimado)';
                        }),

                    Select::make('periodicity')
                        ->label('Periodicidad')
                        ->options(Periodicity::class)
                        ->default($record->periodicity)
                        ->helperText('Frecuencia de pago de las cuotas'),

                    DatePicker::make('start_date')
                        ->label('Fecha de inicio')
                        ->default(fn () => self::getDefaultStartDate($record))
                        ->required()
                        ->helperText(fn () => self::getStartDateHelperText($record)),

                    DatePicker::make('first_due_date_override')
                        ->label('Primera fecha de vencimiento (opcional)')
                        ->helperText('Dejar vacío para calcular automáticamente'),
                ])
                ->columns(2),

            // Motivo de la prórroga
            Textarea::make('reason')
                ->label('Motivo de la prórroga')
                ->placeholder('Ej: Cliente solicitó extensión por dificultades económicas temporales. Se aplica 1 mes de intereses adicionales...')
                ->rows(3)
                ->required()
                ->columnSpanFull()
                ->helperText('Documento el motivo para auditoría'),

            // Advertencia informativa
            Section::make('Información Importante')
                ->schema([
                    Placeholder::make('warning')
                        ->hiddenLabel()
                        ->content(function () use ($record) {
                            $paidCount = $record->installments()->where('status', Installment::STATUS_PAID)->count();

                            return new HtmlString("
                                <div class='rounded-lg bg-warning-50 dark:bg-warning-950 p-4 ring-1 ring-warning-200 dark:ring-warning-800'>
                                    <div class='text-sm text-warning-700 dark:text-warning-300'>
                                        <ul class='list-disc space-y-1 pl-5'>
                                            <li><strong>{$paidCount} cuota(s) pagada(s)</strong> permanecerán intactas en el crédito original.</li>
                                            <li>El crédito original será marcado como <strong>\"Extendido\"</strong> y no podrá modificarse.</li>
                                            <li>Se creará un <strong>nuevo crédito hijo</strong> con el saldo pendiente más los intereses adicionales.</li>
                                            <li>Los pagos históricos y registros de ingresos <strong>NO serán afectados</strong>.</li>
                                            <li>Esta operación <strong>no genera movimiento de caja</strong> (no hay desembolso).</li>
                                        </ul>
                                    </div>
                                </div>
                            ");
                        }),
                ])
                ->collapsed(),
        ];
    }

    /**
     * Ejecuta la acción de prórroga.
     */
    private static function executeAction(array $data, Credit $record): mixed
    {
        try {
            $dto = new ExtendWithInterestData(
                creditId: $record->id,
                newInstallmentsCount: (int) $data['new_installments'],
                additionalInterestPeriods: (int) ($data['additional_interest_periods'] ?? 1),
                newInterestRate: isset($data['new_interest_rate'])
                    ? (string) $data['new_interest_rate']
                    : null,
                periodicity: self::extractPeriodicity($data['periodicity'] ?? null),
                startDate: isset($data['start_date']) ? Carbon::parse($data['start_date']) : null,
                firstDueDateOverride: isset($data['first_due_date_override'])
                    ? Carbon::parse($data['first_due_date_override'])
                    : null,
                reason: $data['reason'] ?? null,
            );

            $result = app(CreditOperationOrchestrator::class)->extendWithInterest($dto);

            Notification::make()
                ->title('Crédito prorrogado exitosamente')
                ->success()
                ->body($result->getSummaryMessage())
                ->persistent()
                ->send();

            return redirect()->to(
                CreditResource::getUrl('view', ['record' => $result->newCredit])
            );
        } catch (CreditOperationException $e) {
            Notification::make()
                ->title('No se pudo prorrogar el crédito')
                ->danger()
                ->body($e->getMessage())
                ->persistent()
                ->send();

            return null;
        } catch (\Throwable $e) {
            // Log detallado del error para debugging
            Log::error('ExtendWithInterest Error', [
                'message' => $e->getMessage(),
                'class' => get_class($e),
                'file' => $e->getFile(),
                'line' => $e->getLine(),
                'trace' => $e->getTraceAsString(),
                'credit_id' => $record->id,
                'data' => $data,
            ]);

            Notification::make()
                ->title('Error inesperado')
                ->danger()
                ->body('Error: '.class_basename($e).' - '.Str::limit($e->getMessage(), 100))
                ->persistent()
                ->send();

            report($e);

            return null;
        }
    }

    /**
     * Extrae el valor de periodicidad del formulario.
     */
    private static function extractPeriodicity(mixed $periodicity): ?string
    {
        if ($periodicity instanceof Periodicity) {
            return $periodicity->value;
        }

        return $periodicity;
    }

    /**
     * Determina la fecha de inicio por defecto.
     */
    private static function getDefaultStartDate(Credit $record): Carbon
    {
        if ($record->due_date) {
            return Carbon::parse($record->due_date);
        }

        return Carbon::today();
    }

    /**
     * Genera texto de ayuda para la fecha de inicio.
     */
    private static function getStartDateHelperText(Credit $record): string
    {
        if ($record->due_date) {
            $dueDate = Carbon::parse($record->due_date);
            $isOverdue = $dueDate->isPast();

            if ($isOverdue) {
                return sprintf(
                    'Crédito vencido el %s. Se recomienda iniciar desde esa fecha.',
                    $dueDate->format('d/m/Y')
                );
            }

            return sprintf('Fecha de vencimiento original: %s', $dueDate->format('d/m/Y'));
        }

        return 'Fecha desde la cual inicia el nuevo crédito';
    }
}
