<?php

namespace App\Livewire\Monitoring;

use App\Models\Auth\User;
use App\Models\Monitoring\Log as MonitoringLog;
use App\Services\System\LimpiezaDelPanel;
use Illuminate\Support\Carbon;
use LivewireUI\Modal\ModalComponent;

/**
 * Limpieza del registro de acciones del panel (`logs`).
 *
 * **La tabla no la borraba nada.** Ni tarea programada, ni retención, ni una sola pantalla:
 * en Tamaño de la base salía como «Ninguna. Es el rastro de quién hizo qué» y eso era todo.
 * Y encima lleva `SoftDeletes`, así que una fila borrada en su día seguía ocupando sitio.
 *
 * ## Lo que esta modal tiene que dejar claro
 *
 * 1. **Es la auditoría.** No es telemetría que sobre: es quién cambió un umbral, quién
 *    bloqueó una IP y quién borró una versión. Por eso los criterios son los mismos con los
 *    que se consulta la pantalla —fechas, nivel, código, usuario—: se borra lo que se ha
 *    mirado antes, no «lo anterior a N días».
 * 2. **Se borra de verdad.** Un `delete()` sobre este modelo solo rellena `deleted_at` y la
 *    fila se queda. Aquí se usa `forceDelete()`, que es lo que hace bajar la tabla.
 * 3. **El borrado se apunta** —código 16041, con cuántas filas y con qué criterios— y esa
 *    fila no se borra a sí misma. Vaciar la auditoría sin dejar rastro sería justo lo que
 *    haría alguien tapando algo.
 */
class LimpiezaDeAccionesModal extends ModalComponent
{
    public string $desde = '';

    public string $hasta = '';

    /** Opcional: `info`, `warning` o `error`. */
    public string $nivel = '';

    /** Opcional: uno de los códigos de {@see MonitoringLog::CODIGOS}. */
    public string $codigo = '';

    /** Opcional: solo lo que hizo una persona. */
    public string $usuario = '';

    public function mount(): void
    {
        // El permiso de la ruta no se reaplica en /livewire/update (MGR-005). Y **no vale el
        // de leer**: la pantalla la ven Admin, Support y Manager, y vaciar la auditoría es
        // cosa de Admin.
        $this->authorize('admin.configs.edit');

        // Un año atrás hasta hace treinta días: abrir con un rango que incluya hoy invita a
        // un clic que se lleva el rastro de lo que se está haciendo ahora mismo.
        $this->desde = now()->subYear()->format('Y-m-d');
        $this->hasta = now()->subDays(30)->format('Y-m-d');
    }

    public static function modalMaxWidth(): string
    {
        return '2xl';
    }

    protected function rules(): array
    {
        return [
            'desde' => ['required', 'date'],
            'hasta' => ['required', 'date', 'after_or_equal:desde'],
            'nivel' => ['nullable', 'in:info,warning,error'],
            'codigo' => ['nullable', 'string', 'max:10'],
            'usuario' => ['nullable', 'integer'],
        ];
    }

    protected function messages(): array
    {
        return [
            'hasta.after_or_equal' => 'La fecha final no puede ser anterior a la inicial.',
        ];
    }

    /** Los criterios ya normalizados, que es lo que entiende el servicio. */
    private function criterios(): ?array
    {
        try {
            $desde = Carbon::parse($this->desde)->startOfDay();
            $hasta = Carbon::parse($this->hasta)->endOfDay();
        } catch (\Throwable) {
            return null;
        }

        if ($hasta->lt($desde)) {
            return null;
        }

        return [
            'desde' => $desde,
            'hasta' => $hasta,
            'nivel' => $this->nivel !== '' ? $this->nivel : null,
            'codigo' => $this->codigo !== '' ? $this->codigo : null,
            'usuario' => $this->usuario !== '' ? (int) $this->usuario : null,
        ];
    }

    /**
     * Cuántas filas se llevaría, recalculado en cada cambio del formulario.
     *
     * @return array{filas: int, enLaPapelera: int}
     */
    public function impacto(): array
    {
        $criterios = $this->criterios();

        if ($criterios === null) {
            return ['filas' => 0, 'enLaPapelera' => 0];
        }

        return [
            'filas' => LimpiezaDelPanel::contarAcciones($criterios),
            // **Las que ya estaban «borradas» y seguían ahí.** Es el dato que explica por qué
            // la tabla no baja cuando alguien borra desde la pantalla.
            'enLaPapelera' => (clone LimpiezaDelPanel::acciones($criterios))
                ->whereNotNull('deleted_at')
                ->count(),
        ];
    }

    /** Las personas que han dejado rastro, para el desplegable. */
    public function usuarios()
    {
        return User::query()
            ->whereIn('id', MonitoringLog::withTrashed()->whereNotNull('user_id')->distinct()->pluck('user_id'))
            ->orderBy('name')
            ->get(['id', 'name']);
    }

    public function borrar(): void
    {
        $this->authorize('admin.configs.edit');
        $this->validate();

        $criterios = $this->criterios();

        if ($criterios === null) {
            return;
        }

        $comoSeAcoto = $this->comoSeAcoto($criterios);
        $borradas = LimpiezaDelPanel::borrarAcciones($criterios);

        // **Después de borrar, y por eso sobrevive**: la fila se escribe cuando el rango ya
        // se ha vaciado, así que no entra en su propio borrado.
        MonitoringLog::db(
            'warning',
            '16041',
            $borradas . ' acciones borradas del registro del panel (' . $comoSeAcoto . ')',
            'logs',
            null
        );

        $this->closeModal();

        $this->dispatch('accionesLimpiadas');

        session()->flash('success', $borradas === 0
            ? 'No había ninguna acción que encajara con esos criterios.'
            : $borradas . ' acciones borradas definitivamente. Queda apuntado quién lo hizo.');
    }

    /** Los criterios en una frase, para el rastro. Sin esto el apunte no dice nada. */
    private function comoSeAcoto(array $criterios): string
    {
        $partes = [
            'del ' . $criterios['desde']->format('d/m/Y') . ' al ' . $criterios['hasta']->format('d/m/Y'),
        ];

        if ($criterios['nivel'] !== null) {
            $partes[] = 'nivel ' . $criterios['nivel'];
        }

        if ($criterios['codigo'] !== null) {
            $partes[] = 'código ' . $criterios['codigo'];
        }

        if ($criterios['usuario'] !== null) {
            $partes[] = 'usuario #' . $criterios['usuario'];
        }

        return implode(', ', $partes);
    }

    public function render()
    {
        return view('livewire.monitoring.limpieza-de-acciones-modal', [
            'impacto' => $this->impacto(),
            'usuarios' => $this->usuarios(),
        ]);
    }
}
