<?php

namespace App\Livewire\Configurations\Environments;

use App\Livewire\Configurations\Envs\BorrarUsoModal;
use App\Models\Environments\Env;
use App\Models\Environments\Environment;
use App\Models\Environments\Type;
use Livewire\Attributes\On;
use Livewire\Attributes\Url;
use Livewire\Component;

/**
 * Catálogos: los tipos de entorno — desde `Configuración.dc.html`.
 *
 * **Qué es un tipo.** La plataforma que declara cada sitio —Moodle LMS, Workplace,
 * WordPress, Goodle—. Se rellenó al montar el Manager y casi no se toca, pero de ella
 * depende qué productos son compatibles con cada entorno.
 *
 * **Qué se arregla aquí:**
 *
 * - **No decía cuántos entornos usa cada tipo.** Cuatro columnas —icono, nombre,
 *   shortname, descripción— y ni una pista de que uno de los cuatro tipos tiene 15
 *   entornos colgando y otro tiene uno.
 * - **No se podía borrar.** La línea del botón estaba comentada y apuntaba a una ruta
 *   inexistente; el permiso tampoco existía. Ver `TypeDeleteModal`.
 * - **Era una tabla dentro de una pantalla con pestañas dentro de pestañas.** Ahora es
 *   la hoja «Catálogos» de la sección, con su vuelta a la portada.
 *
 * Ya no pagina: son cuatro tipos y la paginación ocupaba más que la tabla. Si algún día
 * son treinta, se vuelve a poner —y entonces el buscador servirá para algo—.
 */
class Index extends Component
{
    /**
     * Búsqueda por nombre o descripción.
     *
     * En la URL —`?q=`— como en el resto del panel. Se conserva del componente anterior,
     * que ya la tenía en el query string.
     */
    #[Url(as: 'q', except: '')]
    public string $search = '';

    /**
     * Tras borrar un tipo o un uso, el listado se vuelve a pintar sin él.
     *
     * Los dos eventos al mismo método: el render de Livewire ya recarga las consultas, y
     * el listener existe para que el evento del modal llegue a algún sitio.
     */
    #[On('typesChanged')]
    #[On('usosCambiados')]
    public function refrescar(): void
    {
    }

    /**
     * Borrar un uso del entorno.
     *
     * **El uso no es el tipo.** El tipo es la plataforma —Moodle LMS, Workplace— y el uso
     * es para qué sirve el sitio —producción, previo, desarrollo, local—. Se gestionan en
     * la misma hoja porque son los dos catálogos de un entorno, con dos permisos distintos.
     */
    public function abrirBorradoDeUso(int $usoId): void
    {
        $this->authorize('admin.configurations.envs.destroy');

        $this->dispatch('openModal',
            component: BorrarUsoModal::class,
            arguments: ['usoId' => $usoId]
        );
    }

    public function abrirBorrado(int $typeId): void
    {
        $this->authorize('admin.configurations.environments-types.destroy');

        $this->dispatch('openModal',
            component: TypeDeleteModal::class,
            arguments: ['typeId' => $typeId]
        );
    }

    public function render()
    {
        $types = Type::query()
            // Los entornos y los productos, en la misma consulta: contarlos por fila era
            // el N+1 de MGR-016, y con `products_count` la modal de borrado ya no tiene
            // que volver a preguntarlo.
            ->withCount(['environments', 'products'])
            ->when($this->search !== '', function ($consulta) {
                // Agrupado: sin el paréntesis, el `orWhere` se saldría de cualquier
                // filtro que se añada después. Es MGR-054.
                $consulta->where(function ($q) {
                    $q->where('name', 'like', '%' . $this->search . '%')
                        ->orWhere('shortname', 'like', '%' . $this->search . '%')
                        ->orWhere('description', 'like', '%' . $this->search . '%');
                });
            })
            // Los que más entornos tienen primero: son los que importan, y de paso los
            // que no se pueden borrar quedan arriba.
            ->orderByDesc('environments_count')
            ->orderBy('name')
            ->get();

        // ============ Los usos del entorno ============
        //
        // **Sin buscador y sin paginar**, a diferencia de los tipos: son cuatro y crecen
        // de uno en uno. Y con el recuento de entornos en la misma consulta, porque es lo
        // que decide si la fila se puede borrar y sin él la modal tendría que preguntarlo
        // otra vez.
        //
        // El recuento es por `shortname` y no por clave ajena: `environments.env` guarda la
        // cadena, porque ese valor lo manda cada Moodle en el payload de la API.
        $porUso = Environment::query()
            ->selectRaw('env, count(*) as cuantos')
            ->whereNotNull('env')
            ->groupBy('env')
            ->pluck('cuantos', 'env');

        $usos = Env::catalogo()->map(fn (Env $uso) => [
            'id' => $uso->id,
            'shortname' => $uso->shortname,
            'name' => $uso->name,
            'description' => $uso->description,
            'color' => $uso->color(),
            'visible_por_defecto' => $uso->visible_por_defecto,
            'protegido' => $uso->esExentoDelIndice(),
            'entornos' => (int) ($porUso[$uso->shortname] ?? 0),
        ]);

        return view('livewire.configurations.environments.index', [
            'usos' => $usos,
            // Los `env` guardados que el catálogo no reconoce. Deberían ser cero —la
            // migración dio de alta los que encontró—, pero si alguien borra un uso que
            // luego vuelve a llegar por la API, esos entornos se quedan descolgados: el
            // filtro no los encuentra y su sync se rechaza. Enseñarlo aquí es la única
            // forma de que se vea.
            'usosHuerfanos' => $porUso->keys()
                ->reject(fn ($env) => Env::existe((string) $env))
                ->values()
                ->all(),
            'types' => $types,
            'totalEntornos' => $types->sum('environments_count'),
            // El otro catálogo de la sección: la lista de plugins propios. Se enseñan
            // los primeros y no solo el contador —un catálogo detrás de un enlace que
            // dice «12 declarados» obliga a entrar para saber si está el que buscas—, y
            // el orquestador va primero porque no es un plugin más de la lista.
            'cuantosPropios' => \App\Models\Products\OwnPlugin::count(),
            'propios' => \App\Models\Products\OwnPlugin::orderBy('component')
                ->get()
                ->map(fn (\App\Models\Products\OwnPlugin $p) => [
                    'component' => $p->component,
                    'name' => $p->name ?: $p->component,
                    'orquestador' => $p->component === \App\Models\Products\OwnPlugin::ORQUESTADOR,
                ])
                ->sortByDesc(fn (array $p) => $p['orquestador'])
                ->take(10)
                ->values(),
        ])->layout('layouts.app');
    }
}
