<?php

use App\Http\Middleware\EnsurePwaAccess;
use App\Http\Middleware\EnsurePwaCollector;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
use Livewire\Mechanisms\HandleComponents\CorruptComponentPayloadException;
use Sentry\Laravel\Integration;

// ✅ Necesario para el Scheduler

return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        api: __DIR__.'/../routes/api.php', // ✅ Mantener API
        commands: __DIR__.'/../routes/console.php', // ✅ Aquí van tus comandos
        health: '/up',
    )
    ->withMiddleware(function (Middleware $middleware) {
        $middleware->trustProxies(at: '*');

        // Alias para middleware PWA
        $middleware->alias([
            'pwa.collector' => EnsurePwaCollector::class,
            'pwa.access' => EnsurePwaAccess::class,
        ]);
    })
    ->withExceptions(function (Exceptions $exceptions) {
        // Reporta a Sentry (Laravel 11+ requiere engancharlo explícitamente).
        // Respeta el dontReport/report de abajo: lo silenciado no se envía.
        Integration::handles($exceptions);

        // #59 — Ruido benigno de Livewire por snapshots viejos/incompatibles:
        // pestañas dejadas abiertas que reintentan el polling de notificaciones
        // de Filament (cada 30s) tras un deploy, o bots POSTeando a
        // /livewire/update. No corrompe datos ni rompe el panel; solo ensucia
        // el log y puede ocultar errores reales.

        // CorruptComponentPayloadException ya se maneja sola: en producción
        // devuelve un 419 y la pestaña se refresca. No hace falta loguearla.
        $exceptions->dontReport([
            CorruptComponentPayloadException::class,
        ]);

        // El mismo payload viejo dispara un TypeError al rehidratar la
        // Filament\Notifications\Collection (su closure exige `array` y recibe
        // un `int`). No es bug propio (tabla `notifications` vacía, API estándar)
        // y no se puede parchear el vendor, así que se silencia SOLO ese
        // TypeError puntual —identificado por su mensaje— para no ocultar
        // ningún otro TypeError real.
        $exceptions->report(function (TypeError $e): ?bool {
            if (str_contains($e->getMessage(), 'Filament\Notifications\Collection')
                && str_contains($e->getMessage(), 'must be of type array')) {
                return false; // no propagar al logging por defecto
            }

            return null; // resto de TypeError: comportamiento normal
        });
    })
    ->withSchedule(function (Schedule $schedule) {
        $log = storage_path('logs/schedule.log');

        // ── Noche (00:xx) ─────────────────────────────────────────────────────
        $schedule->command('subscriptions:update-status')
            ->dailyAt('00:00')
            ->withoutOverlapping()
            ->onOneServer()
            ->appendOutputTo($log);

        $schedule->command('credits:update-installments')
            ->dailyAt('00:05')
            ->withoutOverlapping()
            ->onOneServer()
            ->appendOutputTo($log);

        // Reconcilia estados de créditos usando SmartCreditStateResolver.
        // Respeta days_until_delayed / days_until_default, excluye padres e inmutables.
        $schedule->command('credits:reconcile-status --apply')
            ->dailyAt('00:10')
            ->withoutOverlapping()
            ->onOneServer()
            ->appendOutputTo($log);

        // ── Mañana (08:xx) ────────────────────────────────────────────────────
        // Avisos in-app de vencimiento (prueba/suscripción/gracia) a T-3 y T-1 días.
        // Corre tras update-status (00:00), con los estados ya frescos (#166).
        $schedule->command('subscriptions:notify-expiring')
            ->dailyAt('08:00')
            ->withoutOverlapping()
            ->onOneServer()
            ->appendOutputTo($log);

        // ── Fin de día (23:xx) ────────────────────────────────────────────────
        // Snapshot diario real de PAR — captura el estado de fin de día.
        // Idempotente: usa updateOrCreate por (company_id, snapshot_date).
        $schedule->command('credify:snapshot-par')
            ->dailyAt('23:50')
            ->withoutOverlapping()
            ->onOneServer()
            ->appendOutputTo($log);

        // Snapshot diario de métricas financieras del dashboard (base de las flechas
        // de tendencia semana-sobre-semana). Tras el de PAR. Idempotente.
        $schedule->command('credify:snapshot-dashboard')
            ->dailyAt('23:55')
            ->withoutOverlapping()
            ->onOneServer()
            ->appendOutputTo($log);

        // ── Semanal ───────────────────────────────────────────────────────────
        // Red de seguridad: corrige créditos con saldo $0 que no pasaron a 'paid'.
        $schedule->command('credify:fix-completed-credits --apply')
            ->weeklyOn(0, '03:00')
            ->withoutOverlapping()
            ->onOneServer()
            ->runInBackground()
            ->appendOutputTo($log);

        // ── Higiene de accesos ────────────────────────────────────────────────
        // Los tokens de la PWA caducan a los 30 dias pero NADIE los borraba: la
        // tabla acumulo 1.411 filas, 826 de ellas ya expiradas, para una empresa
        // de 3 usuarios. `--hours=24` conserva las recien vencidas por si hay que
        // investigar un acceso.
        $schedule->command('sanctum:prune-expired --hours=24')
            ->weeklyOn(1, '03:30')
            ->onOneServer()
            ->appendOutputTo($log);

        // ── Demo ──────────────────────────────────────────────────────────────
        // Reset nocturno incondicional: la demo compartida amanece siempre fresca.
        $schedule->command('credify:reset-demo --force')
            ->dailyAt('04:00')
            ->withoutOverlapping()
            ->onOneServer()
            ->appendOutputTo($log);

        // Reset intra-día si algún indicador de uso del plan llega al 90%: evita
        // que la demo se vea "llena"/agotada durante el día sin esperar al de las 4am.
        $schedule->command('credify:reset-demo --threshold=90')
            ->cron('0 9,12,15,18,21 * * *')
            ->withoutOverlapping()
            ->onOneServer()
            ->appendOutputTo($log);
    })
    ->create();
