<?php

declare(strict_types=1);

namespace App\Filament\Widgets\Admin;

use App\Services\Metrics\DelinquencyMetricsService;
use Filament\Support\RawJs;
use Illuminate\Support\Facades\Auth;
use Leandrocfe\FilamentApexCharts\Widgets\ApexChartWidget;

/**
 * Gráfico de Salud de Cartera — Distribución por Antigüedad de Mora.
 *
 * Motor: ApexCharts (leandrocfe/filament-apex-charts ^5.0)
 *
 * Tipo: Barras distribuidas (cada tramo con su propio color de severidad).
 * El conteo de créditos se muestra en el tooltip junto al saldo, sin necesidad
 * de un segundo eje Y ni de un dataset de línea separado.
 *
 * Paleta de colores: verde → amarillo → naranja → rojo → granate → morado.
 * Escala visual de riesgo creciente de izquierda a derecha.
 *
 * Datos: DelinquencyMetricsService::getAgingReport() — TTL 5 min (cache 'standard').
 */
class PortfolioAgingChart extends ApexChartWidget
{
    protected static ?string $chartId = 'portfolioAgingChart';

    protected static ?string $heading = 'Salud de Cartera — Antigüedad de Mora';

    protected ?string $pollingInterval = '300s';

    protected static ?int $sort = 1;

    // columnSpan = 1 → ocupa 1 de las 2 columnas del grid Admin (mitad izquierda).
    protected int|string|array $columnSpan = 1;

    /** Datos calculados una sola vez por request de render. */
    private ?array $cachedAgingData = null;

    public static function canView(): bool
    {
        $user = Auth::user();

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

    protected function getOptions(): array
    {
        $data = $this->buildAgingData();

        return [
            'chart' => [
                'type' => 'bar',
                'height' => 400,
                'toolbar' => ['show' => false],
            ],
            'series' => [
                [
                    'name' => 'Saldo en mora',
                    'data' => $data['balances'],
                ],
            ],
            'xaxis' => [
                'categories' => $data['labels'],
                'labels' => [
                    'style' => ['colors' => '#9ca3af', 'fontWeight' => 600],
                ],
            ],
            'yaxis' => [
                'labels' => [
                    'style' => ['colors' => '#9ca3af', 'fontWeight' => 600],
                ],
            ],
            // distributed = true: cada barra recibe su propio color del array 'colors'.
            'colors' => $data['colors'],
            'plotOptions' => [
                'bar' => [
                    'distributed' => true,
                    'borderRadius' => 4,
                    'columnWidth' => '70%',
                ],
            ],
            'dataLabels' => ['enabled' => false],
            // Con distributed=true ApexCharts genera una entrada de leyenda por barra;
            // se oculta para evitar redundancia con las categorías del eje X.
            'legend' => ['show' => false],
            'grid' => [
                'borderColor' => '#e5e7eb',
                'strokeDashArray' => 4,
            ],
        ];
    }

    /**
     * Formatters y tooltip enriquecido.
     *
     * El tooltip muestra saldo + número de créditos por tramo. Los conteos
     * se inyectan como literal JSON para evitar un segundo eje Y y simplificar
     * la estructura del gráfico.
     *
     * Nota: se usa extraJsOptions() (RawJs, texto crudo) y NO getOptions()
     * para los formatters porque getOptions() se serializa vía @js() / json_encode()
     * lo que elimina las funciones JavaScript — causa del error «s[t].call is not a function».
     */
    protected function extraJsOptions(): ?RawJs
    {
        $counts = $this->buildAgingData()['counts'];
        $countsJson = json_encode(array_values($counts));

        $js = <<<JS
        {
            yaxis: {
                labels: {
                    formatter: function(value) {
                        if (value >= 1000000) return '\$' + (value / 1000000).toFixed(1) + 'M';
                        if (value >= 1000)    return '\$' + (value / 1000).toFixed(0) + 'K';
                        return '\$' + value.toLocaleString('es-CO');
                    }
                }
            },
            tooltip: {
                y: {
                    formatter: function(value, { dataPointIndex }) {
                        var counts = {$countsJson};
                        var balance = '\$' + value.toLocaleString('es-CO');
                        var credits = counts[dataPointIndex] !== undefined
                            ? ' — ' + counts[dataPointIndex] + ' crédito(s)'
                            : '';
                        return balance + credits;
                    }
                }
            }
        }
        JS;

        return RawJs::make($js);
    }

    /**
     * Construye arrays de datos desde el reporte de aging.
     * Utiliza memoización interna para evitar doble cómputo entre getOptions() y extraJsOptions().
     *
     * @return array{labels: string[], balances: float[], counts: int[], colors: string[]}
     */
    private function buildAgingData(): array
    {
        if ($this->cachedAgingData !== null) {
            return $this->cachedAgingData;
        }

        $companyId = (int) Auth::user()->company_id;
        $aging = app(DelinquencyMetricsService::class)->getAgingReport($companyId);

        // Paleta de colores — escala de riesgo creciente
        $palette = [
            'current' => '#10b981', // verde    — Al día
            '1_7' => '#f59e0b', // amarillo — 1-7 días
            '8_15' => '#f97316', // naranja  — 8-15 días
            '16_30' => '#ef4444', // rojo     — 16-30 días
            '31_60' => '#b91c1c', // rojo oscuro — 31-60 días
            '61_90' => '#7f1d1d', // granate  — 61-90 días
            '90_plus' => '#581c87', // morado   — >90 días
        ];

        $labels = [];
        $balances = [];
        $counts = [];
        $colors = [];

        foreach ($aging as $key => $bucket) {
            $labels[] = $bucket['label'];
            $balances[] = round($bucket['overdue_balance'], 2);
            $counts[] = $bucket['credits_count'];
            $colors[] = $palette[$key] ?? '#6b7280';
        }

        $this->cachedAgingData = compact('labels', 'balances', 'counts', 'colors');

        return $this->cachedAgingData;
    }
}
