<?php

namespace App\Livewire\Configurations;

use App\Models\Environments\Environment;
use App\Models\Environments\Type;
use App\Models\Products\OwnPlugin;
use App\Services\System\Settings;
use App\Support\Historial;
use Illuminate\Support\Facades\Cache;
use Livewire\Component;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;

/**
 * La portada de Configuración — implementada desde `Configuración.dc.html`.
 *
 * **Lo que había: nada.** No existía ninguna ruta para `/configurations`. El enlace
 * «Configuración» del menú lateral apuntaba directamente a
 * `configurations.catalogs`, o sea que **la puerta de la sección era
 * «Tipos de entornos»** —de las cinco pestañas, la que menos se toca y la que menos
 * explica dónde estás—. Quien entraba veía un catálogo de cuatro plataformas y ninguna
 * pista de que ahí abajo estaban los umbrales que cortan a los clientes.
 *
 * **Y no es un índice de enlaces.** Cada bloque dice **qué gobierna y qué pasa si se
 * cambia**, y arriba se enseña el estado de las cuatro cosas que responden «¿está el
 * Manager configurado como creo?»: si los límites cortan o solo observan, si los avisos
 * salen, cuánto histórico se guarda y cuántos tipos de entorno hay. Son cuatro datos y
 * se ven sin entrar en ningún sitio.
 *
 * **Tres bloques y no cinco pestañas**, porque eran tres cosas distintas con tres
 * públicos distintos puestas al mismo nivel:
 *
 * - **Ajustes** — umbrales, avisos, retención. Es el 90 % de lo que se toca.
 * - **Acceso** — roles y permisos juntos: son la misma pregunta a dos niveles, igual
 *   que pasaba con «Bloqueos» e «IPs» en Monitorización.
 * - **Catálogos** — tipos de entorno, que se rellenaron al montar el Manager.
 *
 * La quinta pestaña, «Productos», **duplicaba `/products`** —dos sitios para crear y
 * editar lo mismo, con permisos distintos— y no está aquí. Ver briefs/configuracion.md
 * §4.4.
 */
class Index extends Component
{
    /**
     * El estado de lo que más importa, sin entrar en ninguna pantalla.
     *
     * Cacheado cinco minutos: `render()` se ejecuta en cada interacción de Livewire y
     * esto son cuatro agregados. Cinco minutos es tolerable porque son datos de
     * configuración, no de operación —y al guardar un ajuste se olvida—.
     *
     * @return array<string, array{titulo: string, valor: string, nota: string, color: ?string}>
     */
    public function estado(): array
    {
        $ajustes = app(Settings::class);

        $corta = $ajustes->losLimitesCortan();
        $retencion = $ajustes->diasDeRetencionDeLogs();

        $avisos = [
            'licencias' => $ajustes->avisaDeLicencias(),
            'soportes' => $ajustes->avisaDeSoportes(),
            'bloqueos' => $ajustes->avisaDeBloqueos(),
        ];
        $activos = count(array_filter($avisos));

        // **Los dos catálogos, no solo los tipos.** La tarjeta decía «4 tipos» cuando
        // Catálogos guarda dos cosas —los tipos de entorno y los plugins propios—, así
        // que el número mentía por omisión: quien buscaba la lista de plugins nuestros no
        // tenía forma de saber que estaba ahí detrás.
        //
        // **La clave lleva versión.** Al añadir `propios` a un array que ya estaba
        // cacheado, la portada reventó con «Undefined array key "propios"»: la caché
        // devolvía la forma vieja durante cinco minutos y el código esperaba la nueva. Si
        // se añade otra clave aquí, hay que subir el `v`.
        $parque = Cache::remember('configs:portada:parque:v2', 300, fn () => [
            'tipos' => Type::count(),
            'entornos' => Environment::count(),
            'propios' => OwnPlugin::count(),
        ]);

        return [
            'limites' => [
                'titulo' => 'Límites de la API',
                'valor' => $corta ? 'Cortando' : 'En observación',
                // La nota dice la consecuencia, que es lo que hace que alguien mire este
                // dato: «en observación» a secas no significa nada para quien no sabe
                // qué modo es el peligroso.
                'nota' => $corta
                    ? 'quien se pasa deja de recibir contenido'
                    : 'se anotan los excesos y no se corta a nadie',
                'color' => $corta ? 'var(--warning-500)' : 'var(--info-500)',
            ],
            'avisos' => [
                'titulo' => 'Avisos por correo',
                'valor' => match ($activos) {
                    3 => 'Todos activos',
                    0 => 'Ninguno activo',
                    default => $activos . ' de 3 activos',
                },
                'nota' => $activos === 0
                    ? 'nadie se enterará de una licencia que caduca'
                    : 'de licencias, soportes y bloqueos',
                'color' => $activos === 0 ? 'var(--warning-500)' : 'var(--success-500)',
            ],
            'retencion' => [
                'titulo' => 'Histórico guardado',
                'valor' => $retencion === 0 ? 'Sin límite' : $retencion . ' días',
                'nota' => $retencion === 0
                    ? 'no se borra nada, y el visor se irá volviendo lento'
                    : 'de peticiones a la API; lo anterior se borra',
                'color' => $retencion === 0 ? 'var(--warning-500)' : null,
            ],
            'parque' => [
                'titulo' => 'Catálogos',
                'valor' => $parque['tipos'] . ' ' . ($parque['tipos'] === 1 ? 'tipo' : 'tipos')
                    . ' · ' . $parque['propios'] . ' ' . ($parque['propios'] === 1 ? 'plugin nuestro' : 'plugins nuestros'),
                // La nota dice para qué sirve cada lista, que es lo que hace que alguien
                // entre: «4 tipos» no explica por qué importa el catálogo.
                'nota' => $parque['propios'] === 0
                    ? 'sin plugins declarados, no se distinguen los nuestros en ningún entorno'
                    : $parque['entornos'] . ' ' . ($parque['entornos'] === 1 ? 'entorno' : 'entornos') . ' repartidos por tipo',
                'color' => $parque['propios'] === 0 ? 'var(--warning-500)' : null,
            ],
        ];
    }

    /**
     * Los roles, con lo que hace falta para saber si el reparto está sano.
     *
     * **Un rol sin permisos se enseña en la portada** porque es el fallo silencioso de
     * esta sección: quien lo tenga entra y no ve una sola pantalla, sin ningún error.
     * Era el caso de Support antes de arreglarlo, y nadie lo veía desde ninguna pantalla.
     *
     * @return array{roles: int, permisos: int, sinPermisos: int}
     */
    public function acceso(): array
    {
        return Cache::remember('configs:portada:acceso', 300, function () {
            $roles = Role::withCount('permissions')->get();

            return [
                'roles' => $roles->count(),
                'permisos' => Permission::count(),
                'sinPermisos' => $roles->where('permissions_count', 0)->count(),
            ];
        });
    }

    public function render()
    {
        return view('livewire.configurations.index', [
            'estado' => $this->estado(),
            'acceso' => $this->acceso(),
            'cuantosAjustes' => Settings::cuantosAjustes(),
            // La versión que corre aquí. No se cachea: son constantes del código, o sea
            // que leerlas cuesta lo mismo que leer la caché.
            'version' => Historial::ACTUAL,
            'donde' => Historial::donde(),
        ])->layout('layouts.app');
    }
}
