<?php

namespace App\Livewire\Monitoring;

use App\Models\Monitoring\Log as MonitoringLog;
use Livewire\Attributes\Url;
use Livewire\Component;
use Livewire\WithPagination;

/**
 * El registro de acciones del panel: quién hizo qué y cuándo.
 *
 * **El hueco que tapa.** La tabla `logs` se escribe desde media aplicación —bajas de
 * cliente, cambios de dominio, renovaciones, borrados de logs, cambios de umbrales,
 * bloqueos manuales de IP— y **no tenía pantalla**. Se veía solo en el bloque «Sistema»
 * del Dashboard: los **5 más recientes**, de los últimos **7 días** y solo de nivel
 * `danger` o `warning`. Todo lo de nivel `info` —una renovación de licencia, por
 * ejemplo— no aparecía en ningún sitio.
 *
 * El propio código lo reconocía: *«Aquí el "ver todo" no tiene a dónde ir: la tabla
 * `logs` no tiene pantalla propia todavía»*. Y había un permiso `admin.logs.index`
 * creado por una migración vieja, **huérfano**, sin ruta ni pantalla (MGR-011): esta
 * pantalla lo recupera, así que deja de ser ruido en la matriz de permisos.
 *
 * Va en Monitorización porque es exactamente eso: algo que se revisa. Los ajustes están
 * en Configuraciones del Manager.
 */
class SystemLog extends Component
{
    use WithPagination;

    /** Filtros en la URL: un log que se está investigando se comparte por enlace. */
    #[Url(as: 'nivel', except: '')]
    public string $nivel = '';

    #[Url(as: 'codigo', except: '')]
    public string $codigo = '';

    #[Url(as: 'q', except: '')]
    public string $busqueda = '';

    /**
     * Quién. Vacío = todos; `0` = las tareas programadas y la API.
     *
     * Es cadena y no int porque el `0` tiene significado propio y un `null` en un
     * `<select>` no se distingue de "sin elegir".
     */
    #[Url(as: 'usuario', except: '')]
    public string $usuario = '';

    #[Url(as: 'desde', except: '')]
    public string $desde = '';

    #[Url(as: 'hasta', except: '')]
    public string $hasta = '';

    public function mount(): void
    {
        $this->authorize('admin.logs.index');
    }

    public function updated(): void
    {
        $this->resetPage();
    }

    public function hayFiltros(): bool
    {
        return $this->nivel !== ''
            || $this->codigo !== ''
            || $this->usuario !== ''
            || trim($this->busqueda) !== ''
            || $this->desde !== ''
            || $this->hasta !== '';
    }

    /**
     * Abre la limpieza de la tabla.
     *
     * **`logs` no la borraba nada**: ni tarea, ni retención, ni pantalla. Y lleva borrado
     * lógico, así que lo que alguien «borró» en su día seguía ocupando sitio. Va en una modal
     * y no en una tarea programada por decisión de Producto (2026-09-15): esto es auditoría,
     * y caducarla por un plazo que nadie ha pensado es perder pruebas.
     */
    public function abrirLimpieza(): void
    {
        // Mirar la pantalla es `admin.logs.index`; vaciarla es cosa de Admin. MGR-005.
        $this->authorize('admin.configs.edit');

        $this->dispatch('openModal', component: LimpiezaDeAccionesModal::class);
    }

    /** Vuelve a contar cuando la modal termina. */
    #[\Livewire\Attributes\On('accionesLimpiadas')]
    public function refrescar(): void
    {
        $this->resetPage();
    }

    public function limpiarFiltros(): void
    {
        $this->reset(['nivel', 'codigo', 'usuario', 'busqueda', 'desde', 'hasta']);
        $this->resetPage();
    }

    public function render()
    {
        $filas = MonitoringLog::query()
            ->with('user')
            ->when($this->nivel !== '', fn ($q) => $q->where('level', $this->nivel))
            // El 0 es "nadie": tareas programadas y la propia API. Es una opción real,
            // no la ausencia de filtro.
            ->when($this->usuario === '0', fn ($q) => $q->whereNull('user_id'))
            ->when($this->usuario !== '' && $this->usuario !== '0', fn ($q) => $q->where('user_id', (int) $this->usuario))
            ->when($this->codigo !== '', fn ($q) => $q->where('code', $this->codigo))
            ->when(
                trim($this->busqueda) !== '',
                fn ($q) => $q->where('msg', 'like', '%' . trim($this->busqueda) . '%')
            )
            // `whereDate` y no una comparación con Carbon: `created_at` es datetime y
            // comparar contra las 00:00 del día «hasta» dejaría fuera ese día entero.
            // Misma trampa que en `DataAction`.
            ->when($this->desde !== '', fn ($q) => $q->whereDate('created_at', '>=', $this->desde))
            ->when($this->hasta !== '', fn ($q) => $q->whereDate('created_at', '<=', $this->hasta))
            ->orderByDesc('created_at')
            ->paginate(30);

        return view('livewire.monitoring.system-log', [
            'filas' => $filas,
            // Solo quien aparece de verdad en el registro: la lista de todos los
            // usuarios del sistema haría buscar entre cuentas que no han hecho nada.
            'responsables' => \App\Models\Auth\User::whereIn(
                'id',
                MonitoringLog::query()->whereNotNull('user_id')->distinct()->pluck('user_id')
            )->orderBy('name')->pluck('name', 'id')->all(),
            'hayDeSistema' => MonitoringLog::whereNull('user_id')->exists(),
            'hayFiltros' => $this->hayFiltros(),
            // Y solo los códigos que existen: un desplegable con los 22 del catálogo,
            // de los que la mayoría no se ha usado nunca, hace buscar entre opciones
            // vacías.
            'codigosUsados' => MonitoringLog::query()
                ->select('code')
                ->distinct()
                ->orderBy('code')
                ->pluck('code')
                ->all(),
        ])->layout('layouts.app');
    }
}
