<?php

declare(strict_types=1);

namespace App\Filament\Widgets\Admin;

use App\Models\User;
use App\Services\Metrics\DelinquencyMetricsService;
use App\Services\Metrics\PortfolioMetricsService;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
use Filament\Widgets\TableWidget as BaseWidget;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Auth;

/**
 * Tabla de desempeño de collectors.
 *
 * Muestra métricas clave por collector:
 * - Créditos asignados, cartera, cobrado este mes
 * - Tasa de morosidad, PAR30
 */
class CollectorPerformanceTable extends BaseWidget
{
    protected static ?string $heading = 'Desempeño de Collectors';

    protected static ?string $description = 'Métricas de cartera y cobranza por collector';

    protected static ?int $sort = 7;

    protected int|string|array $columnSpan = 'full';

    /**
     * Solo visible para Admins de company.
     */
    public static function canView(): bool
    {
        $user = Auth::user();

        return $user && $user->hasRole('admin') && ! $user->isSuperAdmin();
    }

    /**
     * Carga las métricas una sola vez y las cachea durante el request.
     */
    protected function getPerformanceData(): Collection
    {
        static $cached = null;

        if ($cached !== null) {
            return $cached;
        }

        $companyId = Auth::user()->company_id;

        $portfolioByCollector = app(PortfolioMetricsService::class)
            ->getMetricsByCollector($companyId);

        $delinquencyByCollector = app(DelinquencyMetricsService::class)
            ->getDelinquencyByCollector($companyId);

        $cached = collect($portfolioByCollector)->map(function ($portfolio) use ($delinquencyByCollector) {
            $delinquency = $delinquencyByCollector
                ->firstWhere('collector_id', $portfolio['collector_id']);

            return [
                'collector_id' => $portfolio['collector_id'],
                'credits_count' => $portfolio['credits_count'],
                'portfolio_balance' => $portfolio['portfolio_balance'],
                'collected_month' => $portfolio['collected_month'],
                'overdue_count' => $portfolio['overdue_count'],
                'delinquency_rate' => $portfolio['delinquency_rate'],
                'par30' => $delinquency['par30'] ?? 0,
            ];
        })->keyBy('collector_id');

        return $cached;
    }

    public function table(Table $table): Table
    {
        $companyId = Auth::user()->company_id;
        $performance = $this->getPerformanceData();
        $collectorIds = $performance->keys()->toArray();

        return $table
            ->query(
                User::query()
                    ->where('company_id', $companyId)
                    ->whereIn('id', $collectorIds)
            )
            ->columns([
                TextColumn::make('name')
                    ->label('Collector')
                    ->searchable()
                    ->sortable(),

                TextColumn::make('credits_count')
                    ->label('Créditos')
                    ->getStateUsing(fn (User $record) => $performance[$record->id]['credits_count'] ?? 0)
                    ->alignEnd()
                    ->sortable(query: fn (Builder $q, string $direction) => $this->sortByMetric($q, $direction, 'credits_count')),

                TextColumn::make('portfolio_balance')
                    ->label('Cartera')
                    ->getStateUsing(fn (User $record) => $performance[$record->id]['portfolio_balance'] ?? 0)
                    ->money('COP', locale: 'es_CO')
                    ->alignEnd()
                    ->sortable(query: fn (Builder $q, string $direction) => $this->sortByMetric($q, $direction, 'portfolio_balance')),

                TextColumn::make('collected_month')
                    ->label('Cobrado Mes')
                    ->getStateUsing(fn (User $record) => $performance[$record->id]['collected_month'] ?? 0)
                    ->money('COP', locale: 'es_CO')
                    ->color('success')
                    ->weight('bold')
                    ->alignEnd()
                    ->sortable(query: fn (Builder $q, string $direction) => $this->sortByMetric($q, $direction, 'collected_month')),

                TextColumn::make('overdue_count')
                    ->label('En Mora')
                    ->getStateUsing(fn (User $record) => $performance[$record->id]['overdue_count'] ?? 0)
                    ->alignEnd()
                    ->color(fn ($state) => $state > 0 ? 'danger' : 'gray'),

                TextColumn::make('delinquency_rate')
                    ->label('% Mora')
                    ->getStateUsing(function (User $record) use ($performance) {
                        return number_format($performance[$record->id]['delinquency_rate'] ?? 0, 1).'%';
                    })
                    ->badge()
                    ->color(function (User $record) use ($performance) {
                        $rate = $performance[$record->id]['delinquency_rate'] ?? 0;

                        return match (true) {
                            $rate <= 5 => 'success',
                            $rate <= 15 => 'warning',
                            default => 'danger',
                        };
                    })
                    ->alignEnd(),

                TextColumn::make('par30')
                    ->label('PAR30')
                    ->getStateUsing(function (User $record) use ($performance) {
                        return number_format($performance[$record->id]['par30'] ?? 0, 2).'%';
                    })
                    ->badge()
                    ->color(function (User $record) use ($performance) {
                        $par = $performance[$record->id]['par30'] ?? 0;

                        return match (true) {
                            $par <= 2 => 'success',
                            $par <= 5 => 'info',
                            $par <= 10 => 'warning',
                            default => 'danger',
                        };
                    })
                    ->alignEnd(),
            ])
            ->defaultSort('collected_month', 'desc')
            ->paginated(false)
            ->emptyStateHeading('Sin collectors asignados')
            ->emptyStateDescription('No hay créditos asignados a collectors en este momento.')
            ->emptyStateIcon('heroicon-o-user-group')
            ->poll('120s');
    }

    /**
     * Ordena la query según una métrica del servicio.
     */
    protected function sortByMetric(Builder $query, string $direction, string $metric): Builder
    {
        $performance = $this->getPerformanceData();

        $sortedIds = $performance
            ->sortBy($metric, SORT_REGULAR, $direction === 'desc')
            ->keys()
            ->toArray();

        if (! empty($sortedIds)) {
            $ids = implode(',', array_map('intval', $sortedIds));
            $query->orderByRaw("FIELD(id, {$ids})");
        }

        return $query;
    }
}
