<?php

declare(strict_types=1);

namespace App\Filament\Resources\Credits\Actions;

use App\Actions\RestructureCreditWithCustomInstallmentsAction as BackendAction;
use App\DTOs\CustomInstallmentData;
use App\DTOs\RestructureWithCustomPlanData;
use App\Enums\Periodicity;
use App\Filament\Resources\Credits\CreditResource;
use App\Models\Credit;
use App\Services\CreditManager;
use App\Services\Credits\CreditOperationOrchestrator;
use Carbon\Carbon;
use Filament\Actions\Action;
use Filament\Forms\Components\DatePicker;
use Filament\Forms\Components\Hidden;
use Filament\Forms\Components\Placeholder;
use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Notifications\Notification;
use Filament\Schemas\Components\Actions;
use Filament\Schemas\Components\Section;
use Filament\Schemas\Components\Utilities\Get;
use Filament\Schemas\Components\Utilities\Set;
use Illuminate\Support\HtmlString;

/**
 * Acción de Filament para REESTRUCTURAR un crédito con CUOTAS IRREGULARES.
 *
 * A diferencia de la reestructuración estándar (cuotas iguales), esta acción
 * permite definir montos personalizados para cada cuota, útil para adaptar
 * el plan de pagos a la capacidad de pago del cliente.
 *
 * Ejemplo de uso:
 * - 5 cuotas de $150,000
 * - 1 cuota final de $250,000
 * - Total: debe coincidir con saldo pendiente + intereses capitalizados
 */
class RestructureWithCustomInstallmentsAction
{
    public static function make(): Action
    {
        return Action::make('restructure_custom_installments')
            ->label('Reestructurar (Cuotas Irregulares)')
            ->icon('heroicon-o-table-cells')
            ->color('gray')
            ->modalHeading('Reestructurar con Cuotas Personalizadas')
            ->modalDescription(fn (Credit $record): string => sprintf(
                'Define un plan de pagos con cuotas de montos diferentes. Saldo actual: %s',
                '$ '.number_format(app(CreditManager::class)->getRemainingBalance($record), 2, ',', '.')
            )
            )
            ->modalSubmitActionLabel('Reestructurar Crédito')
            ->modalWidth('2xl')
            ->visible(fn (?Credit $record): bool => filled($record) && app(CreditOperationOrchestrator::class)->canRestructure($record)
            )
            ->schema(fn (Credit $record): array => self::getFormSchema($record))
            ->action(fn (array $data, Credit $record) => self::handleAction($data, $record));
    }

    /**
     * Define el esquema del formulario.
     */
    private static function getFormSchema(Credit $record): array
    {
        $remainingBalance = app(CreditManager::class)->getRemainingBalance($record);

        return [
            // ---------------------------------------------------------------
            // SECCIÓN: Información actual del crédito
            // ---------------------------------------------------------------
            Section::make('Información del crédito actual')
                ->schema([
                    Placeholder::make('current_balance')
                        ->label('Saldo pendiente')
                        ->content(fn () => '$ '.number_format($remainingBalance, 2, ',', '.')),

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

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

            // ---------------------------------------------------------------
            // SECCIÓN: Capitalización de intereses (opcional)
            // ---------------------------------------------------------------
            Section::make('Capitalización de Intereses (Opcional)')
                ->description('Agregue intereses vencidos al capital si es necesario.')
                ->schema([
                    TextInput::make('capitalized_interest')
                        ->label('Intereses a capitalizar')
                        ->numeric()
                        ->minValue(0)
                        ->default(0)
                        ->prefix('$')
                        ->live(onBlur: true)
                        ->helperText('Intereses vencidos que se agregarán al capital'),

                    Placeholder::make('total_to_restructure')
                        ->label('Total a reestructurar')
                        ->content(function (Get $get) use ($remainingBalance) {
                            $capitalized = (float) ($get('capitalized_interest') ?? 0);
                            $total = $remainingBalance + $capitalized;

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

            // ---------------------------------------------------------------
            // SECCIÓN: Configuración opcional
            // ---------------------------------------------------------------
            Section::make('Configuración del nuevo crédito')
                ->schema([
                    TextInput::make('new_interest_rate')
                        ->label('Nueva tasa de interés (%)')
                        ->numeric()
                        ->minValue(0)
                        ->maxValue(100)
                        ->step(0.01)
                        ->default($record->interest_rate)
                        ->suffix('%')
                        ->helperText('Puede ajustar la tasa como parte de la negociación'),

                    Select::make('periodicity')
                        ->label('Periodicidad de referencia')
                        ->options(Periodicity::class)
                        ->default($record->periodicity)
                        ->helperText('Para registro, las fechas se definen manualmente'),
                ])
                ->columns(2)
                ->collapsed(),

            // ---------------------------------------------------------------
            // SECCIÓN: Plan de cuotas personalizadas
            // ---------------------------------------------------------------
            Section::make('Plan de Cuotas Personalizadas')
                ->description('Define cada cuota con su fecha y monto. La suma debe coincidir con el total a reestructurar.')
                ->schema([
                    // Botón para generar plan sugerido
                    Actions::make([
                        Action::make('generate_suggested_plan')
                            ->label('Generar plan sugerido')
                            ->icon('heroicon-o-sparkles')
                            ->color('info')
                            ->action(function (Get $get, Set $set) use ($remainingBalance, $record) {
                                $capitalized = (float) ($get('capitalized_interest') ?? 0);
                                $total = $remainingBalance + $capitalized;
                                $numInstallments = (int) ($get('suggested_installments_count') ?? 6);

                                if ($numInstallments < 1) {
                                    $numInstallments = 6;
                                }

                                // Calcular monto por cuota (igual)
                                $amountPerInstallment = round($total / $numInstallments, 2);
                                $lastAmount = round($total - ($amountPerInstallment * ($numInstallments - 1)), 2);

                                // Generar fechas según periodicidad
                                $periodicity = $get('periodicity') ?? $record->periodicity;
                                $startDate = Carbon::today();

                                $installments = [];
                                for ($i = 1; $i <= $numInstallments; $i++) {
                                    $dueDate = self::calculateDueDate($startDate, $i, $periodicity);
                                    $installments[] = [
                                        'number' => $i,
                                        'due_date' => $dueDate->toDateString(),
                                        'total_amount' => $i === $numInstallments ? $lastAmount : $amountPerInstallment,
                                    ];
                                }

                                $set('installments', $installments);
                            }),
                    ])->columnSpanFull(),

                    TextInput::make('suggested_installments_count')
                        ->label('Número de cuotas para sugerencia')
                        ->numeric()
                        ->default(6)
                        ->minValue(1)
                        ->maxValue(52)
                        ->helperText('Cuántas cuotas generar al usar "Generar plan sugerido"')
                        ->columnSpan(1),

                    Repeater::make('installments')
                        ->label('Cuotas')
                        ->schema([
                            // Campo oculto para preservar el número de cuota
                            Hidden::make('number'),

                            DatePicker::make('due_date')
                                ->label('Fecha de vencimiento')
                                ->required()
                                ->native(false)
                                ->displayFormat('d/m/Y'),

                            TextInput::make('total_amount')
                                ->label('Monto de la cuota')
                                ->numeric()
                                ->required()
                                ->minValue(1)
                                ->prefix('$')
                                ->live(onBlur: true),
                        ])
                        ->columns(2)
                        ->defaultItems(0)
                        ->addActionLabel('Agregar cuota')
                        ->reorderable(false)
                        ->itemLabel(fn (array $state): string => isset($state['number'])
                                ? sprintf('Cuota #%d', (int) $state['number'])
                                : 'Nueva cuota'
                        )
                        ->live()
                        ->columnSpanFull(),

                    // Resumen de validación
                    Placeholder::make('plan_summary')
                        ->label('Resumen del Plan')
                        ->content(function (Get $get) use ($remainingBalance) {
                            $installments = $get('installments') ?? [];
                            $capitalized = (float) ($get('capitalized_interest') ?? 0);

                            if (empty($installments)) {
                                return 'Agregue cuotas para ver el resumen.';
                            }

                            $expectedTotal = $remainingBalance + $capitalized;
                            $planTotal = array_sum(array_column($installments, 'total_amount'));
                            $difference = $planTotal - $expectedTotal;

                            $color = abs($difference) <= 0.01 ? 'green' : 'red';
                            $icon = abs($difference) <= 0.01 ? '✓' : '✗';

                            return new HtmlString(sprintf(
                                '<div class="space-y-1">
                                    <div><strong>Cuotas:</strong> %d</div>
                                    <div><strong>Total del plan:</strong> $ %s</div>
                                    <div><strong>Total esperado:</strong> $ %s</div>
                                    <div style="color: %s;"><strong>Diferencia:</strong> %s $ %s</div>
                                </div>',
                                count($installments),
                                number_format($planTotal, 2, ',', '.'),
                                number_format($expectedTotal, 2, ',', '.'),
                                $color,
                                $icon,
                                number_format(abs($difference), 2, ',', '.')
                            ));
                        })
                        ->columnSpanFull(),
                ]),

            // ---------------------------------------------------------------
            // SECCIÓN: Motivo
            // ---------------------------------------------------------------
            Textarea::make('reason')
                ->label('Motivo de la reestructuración')
                ->placeholder('Ej: Ajuste del plan de pagos a capacidad económica del cliente. Se negocian cuotas progresivas...')
                ->rows(2)
                ->required()
                ->columnSpanFull(),
        ];
    }

    /**
     * Calcula la fecha de vencimiento según la periodicidad.
     *
     * @param  Carbon  $startDate  Fecha de inicio
     * @param  int  $installmentNumber  Número de cuota (1-based)
     * @param  Periodicity|string|null  $periodicity  Periodicidad (enum o string value)
     */
    private static function calculateDueDate(Carbon $startDate, int $installmentNumber, Periodicity|string|null $periodicity): Carbon
    {
        $date = $startDate->copy();

        // Normalizar: extraer string value si es enum
        $periodicityValue = $periodicity instanceof Periodicity
            ? $periodicity->value
            : $periodicity;

        return match ($periodicityValue) {
            'weekly' => $date->addWeeks($installmentNumber),
            'biweekly' => $date->addWeeks($installmentNumber * 2),
            'bimonthly' => $date->addMonths($installmentNumber * 2),
            'quarterly' => $date->addMonths($installmentNumber * 3),
            default => $date->addMonths($installmentNumber), // monthly
        };
    }

    /**
     * Maneja la acción de reestructuración.
     */
    private static function handleAction(array $data, Credit $record): void
    {
        try {
            // Validar que hay cuotas
            $installmentsData = $data['installments'] ?? [];
            if (empty($installmentsData)) {
                throw new \Exception('Debe definir al menos una cuota.');
            }

            // Construir DTOs de cuotas
            $installments = [];
            foreach ($installmentsData as $index => $item) {
                $installments[] = new CustomInstallmentData(
                    number: $index + 1,
                    totalAmount: (float) $item['total_amount'],
                    dueDate: Carbon::parse($item['due_date']),
                );
            }

            // Construir DTO principal
            $dto = new RestructureWithCustomPlanData(
                creditId: $record->id,
                installments: $installments,
                capitalizedInterest: (float) ($data['capitalized_interest'] ?? 0),
                newInterestRate: isset($data['new_interest_rate'])
                    ? (string) $data['new_interest_rate']
                    : null,
                periodicity: isset($data['periodicity']) && $data['periodicity'] instanceof Periodicity
                    ? $data['periodicity']->value
                    : ($data['periodicity'] ?? null),
                reason: $data['reason'] ?? null,
            );

            // Ejecutar la acción
            $result = app(BackendAction::class)->execute($dto);

            Notification::make()
                ->title('Crédito reestructurado exitosamente')
                ->success()
                ->body(sprintf(
                    'Nuevo crédito #%d creado con %d cuotas personalizadas.',
                    $result->newCredit->id,
                    $result->newCredit->installments_count
                ))
                ->persistent()
                ->send();

            redirect()->to(
                CreditResource::getUrl('view', ['record' => $result->newCredit])
            );

        } catch (\InvalidArgumentException $e) {
            Notification::make()
                ->title('Error de validación')
                ->danger()
                ->body($e->getMessage())
                ->persistent()
                ->send();
        } catch (\Exception $e) {
            Notification::make()
                ->title('No se pudo reestructurar el crédito')
                ->danger()
                ->body($e->getMessage())
                ->persistent()
                ->send();

            report($e);
        }
    }
}
