<?php

namespace App\Filament\Resources\Credits\Tables;

use App\Filament\Components\Columns\CreditStatusBadgeColumn;
use App\Filament\Components\Columns\NextInstallmentColumn;
use App\Filament\Resources\Credits\CreditResource;
use App\Filament\Resources\Payments\PaymentResource;
use App\Models\Credit;
use App\Services\CreditCascadeDeletionService;
use Filament\Actions\Action;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\EditAction;
use Filament\Actions\ViewAction;
use Filament\Notifications\Notification;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Table;
use Illuminate\Support\Facades\Gate;

class CreditsTable
{
    public static function configure(Table $table): Table
    {
        return $table
            ->columns([
                // ID interno (PK): oculto por defecto — el crédito se identifica
                // por su "Código" por empresa (001, 002…), no por el id de la BD.
                // Se conserva buscable/toggleable para soporte.
                TextColumn::make('id')
                    ->label('ID interno')
                    ->sortable()
                    ->searchable()
                    ->toggleable(isToggledHiddenByDefault: true),

                TextColumn::make('code')
                    ->label('Código')
                    ->badge()
                    ->color('gray')
                    ->sortable(['company_credit_number'])
                    ->searchable(false),

                TextColumn::make('client.name')
                    ->label('Cliente')
                    ->searchable()
                    ->sortable(),

                TextColumn::make('amount')
                    ->label('Monto')
                    ->money('COP', divideBy: 1, locale: 'es_CO')
                    ->sortable(),

                TextColumn::make('installments_count')
                    ->label('Cuotas')
                    ->sortable(),

                TextColumn::make('periodicity')
                    ->label('Periodicidad')
                    ->badge()
                    ->color(fn ($state) => match ($state) {
                        'weekly' => 'info',
                        'biweekly' => 'warning',
                        'monthly' => 'primary',
                        default => 'gray',
                    })
                    ->formatStateUsing(fn ($state) => match ($state) {
                        'daily' => 'Diario',
                        'weekly' => 'Semanal',
                        'biweekly' => 'Quincenal',
                        'monthly' => 'Mensual',
                        default => $state,
                    })
                    ->sortable(),

                TextColumn::make('due_day_display')
                    ->label('Día de Cobro')
                    ->state(function (Credit $record): string {
                        return match ($record->periodicity) {

                            'weekly' => match ((int) $record->due_day_1) {
                                1 => 'Lunes',
                                2 => 'Martes',
                                3 => 'Miércoles',
                                4 => 'Jueves',
                                5 => 'Viernes',
                                6 => 'Sábado',
                                7 => 'Domingo',
                                default => '—',
                            },

                            'biweekly' => $record->due_day_1 && $record->due_day_2
                                ? "Quincenal ({$record->due_day_1} y {$record->due_day_2})"
                                : 'Quincenal',

                            'monthly' => $record->due_day_1
                                ? "Mensual ({$record->due_day_1})"
                                : 'Mensual',

                            'daily' => 'Diario',

                            default => '—',
                        };
                    })
                    ->badge()
                    ->sortable(query: function ($query, string $direction) {
                        // Orden lógico: primero por periodicidad, luego por día base
                        $query
                            ->orderBy('periodicity', $direction)
                            ->orderBy('due_day_1', $direction)
                            ->orderBy('due_day_2', $direction);
                    }),

                // TextColumn::make('start_date')->label('Inicio')->date()->sortable(),
                // TextColumn::make('due_date')->label('Final')->date()->sortable(),

                // La línea de abajo explica por qué un crédito no está en curso:
                // sin ella, "Extendido" no dice cuál es el crédito que lo sustituyó.
                CreditStatusBadgeColumn::make()
                    ->description(fn (Credit $record): ?string => $record->replacementCode() !== null
                        ? "sustituido por {$record->replacementCode()}"
                        : null),
                // no veo que funcione
                // NextInstallmentColumn::make(),

                TextColumn::make('company.name')
                    ->label('Compañía')
                    ->sortable()
                    ->visible(fn () => auth()->user()->hasRole('super_admin')),
            ])

            ->filters([
                // El recorte grueso (en curso / reemplazados / cerrados) lo hacen
                // las pestañas de ListCredits. Aquí quedan solo los filtros que
                // afinan DENTRO de la pestaña elegida.
                //
                // Antes había un ternario "Archivados" que se contradecía con este
                // select: su valor por defecto excluía `paid` y `canceled`, así que
                // elegir "Pagado" aquí devolvía cero resultados sin decir por qué.
                SelectFilter::make('status')
                    ->label('Estado')
                    ->options(Credit::statusOptions())
                    ->placeholder('Todos los estados')
                    ->searchable(),

                SelectFilter::make('periodicity')
                    ->label('Periodicidad')
                    ->options([
                        'daily' => 'Diario',
                        'weekly' => 'Semanal',
                        'biweekly' => 'Quincenal',
                        'monthly' => 'Mensual',
                    ])
                    ->placeholder('Todas'),

                SelectFilter::make('collection_day')
                    ->label('Día de Cobro')
                    ->options([
                        // Semana
                        1 => 'Lunes',
                        2 => 'Martes',
                        3 => 'Miércoles',
                        4 => 'Jueves',
                        5 => 'Viernes',
                        6 => 'Sábado',
                        7 => 'Domingo',

                        // Separador lógico (UX)
                        '---' => '────────',

                        // Mes
                        15 => 'Día 15',
                        30 => 'Día 30',
                    ])
                    ->query(function ($query, array $data) {
                        if (! isset($data['value']) || $data['value'] === '---') {
                            return;
                        }

                        $day = (int) $data['value'];

                        $query->where(function ($q) use ($day) {

                            // Semanales
                            $q->where(function ($w) use ($day) {
                                $w->where('periodicity', 'weekly')
                                    ->where('due_day_1', $day);
                            })

                            // Quincenales
                                ->orWhere(function ($b) use ($day) {
                                    $b->where('periodicity', 'biweekly')
                                        ->where(function ($d) use ($day) {
                                            $d->where('due_day_1', $day)
                                                ->orWhere('due_day_2', $day);
                                        });
                                })

                            // Mensuales
                                ->orWhere(function ($m) use ($day) {
                                    $m->where('periodicity', 'monthly')
                                        ->where('due_day_1', $day);
                                });
                        });
                    })
                    ->placeholder('Todos'),
            ])

            ->actions([

                // BOTÓN ABONAR
                Action::make('payment')
                    ->label('Abonar')
                    ->color('emerald')
                    ->icon('heroicon-s-banknotes')
                    ->url(fn (Credit $record) => PaymentResource::getUrl('create', ['credit_id' => $record->id])
                    )
                    ->visible(fn (Credit $c) => ! $c->isClosed()),

                ViewAction::make(),

                EditAction::make()
                    ->visible(fn (Credit $c) => ! $c->isClosed() && ! $c->hasPayments()),

                // ELIMINAR CRÉDITO PRO (Policy-driven)
                Action::make('deleteCredit')
                    ->label('Eliminar')
                    ->icon('heroicon-o-trash')
                    ->color('danger')
                    ->requiresConfirmation()
                    ->visible(fn (Credit $c) => Gate::allows('delete', $c))
                    ->modalHeading('Eliminar crédito')
                    ->modalDescription(function (Credit $c) {
                        if (Gate::denies('delete', $c)) {
                            return 'Este crédito tiene pagos registrados y NO puede eliminarse (POLÍTICA A).';
                        }

                        $monto = number_format((float) $c->amount, 0, ',', '.');

                        return "Eliminar borra el crédito y DEVUELVE \${$monto} a la caja (el desembolso registrado). ".
                            'Úsalo solo si el dinero NUNCA salió (error de registro). Si el cliente recibió el dinero, '.
                            'cancela el crédito en su lugar (mantiene el registro y no mueve la caja).';
                    })
                    ->action(function (Credit $record) {
                        Gate::authorize('delete', $record);

                        app(CreditCascadeDeletionService::class)
                            ->deleteCreditCompletely($record);

                        Notification::make()
                            ->title('Crédito eliminado')
                            ->success()
                            ->body("El crédito #{$record->code} fue eliminado correctamente.")
                            ->send();
                    }),

            ])

            ->bulkActions([
                BulkActionGroup::make([
                    Action::make('bulk_delete')
                        ->label('Eliminar créditos seleccionados')
                        ->color('danger')
                        ->requiresConfirmation()
                        ->modalHeading('Eliminar créditos')
                        ->modalDescription('Solo se eliminarán créditos permitidos por POLÍTICA A')
                        ->action(function (array $records) {
                            $service = app(CreditCascadeDeletionService::class);

                            $deleted = 0;
                            $skipped = 0;

                            foreach ($records as $credit) {
                                if (! Gate::allows('delete', $credit)) {
                                    $skipped++;

                                    continue;
                                }

                                $service->deleteCreditCompletely($credit);
                                $deleted++;
                            }

                            Notification::make()
                                ->title('Eliminación completada')
                                ->success()
                                ->body("Eliminados: {$deleted}  ·  Omitidos: {$skipped}")
                                ->send();
                        }),
                ]),
            ])

            ->recordUrl(
                fn (Credit $c) => $c->hasPayments() || $c->isClosed()
                    ? CreditResource::getUrl('view', ['record' => $c])
                    : CreditResource::getUrl('edit', ['record' => $c])
            );
    }
}
