<?php

namespace App\Livewire\Configurations\Envs;

use App\Models\Environments\Env;
use App\Models\Monitoring\Log as MonitoringLog;
use Illuminate\Support\Facades\Auth;
use LivewireUI\Modal\ModalComponent;

/**
 * Borrar un uso del entorno del catálogo.
 *
 * **No se borra si algún entorno lo declara**, y aquí el motivo es más fuerte que en los
 * tipos: `environments.env` guarda la **cadena**, no una clave ajena, así que borrar la fila
 * del catálogo no da ningún error de integridad — deja veinte entornos con un valor que ya
 * no significa nada:
 *
 * 1. El filtro del listado no los encontraría: sus botones salen del catálogo.
 * 2. Su etiqueta se pintaría con el color neutro de reserva, sin decir por qué.
 * 3. Su formulario de edición no podría guardarlos sin cambiarles el uso, porque
 *    `Environment::reglaDeEnv()` valida contra el catálogo.
 * 4. Y `MoodleApiRequest` empezaría a devolver un 422 a esos Moodles en su siguiente
 *    `sync`, hablando de un campo que su configuración lleva bien puesta.
 *
 * O sea que borrar un uso en uso **no falla**: rompe el servicio de esos sitios sin avisar.
 * Por eso se bloquea en lugar de advertir, igual que en el borrado de tipos y de productos.
 *
 * **Y `local` no se borra nunca**, ni con cero entornos: de esa cadena literal depende la
 * columna generada `domain_unique` y la exención del índice único del dominio. Sin la fila
 * en el catálogo no habría forma de dar de alta un sitio exento, y varios desarrolladores
 * no podrían compartir `moodle.test`. Ver {@see Env::esExentoDelIndice()}.
 */
class BorrarUsoModal extends ModalComponent
{
    public Env $uso;

    public function mount(int $usoId): void
    {
        // El permiso de la ruta no se reaplica en /livewire/update. Ver MGR-005.
        $this->authorize('admin.configurations.envs.destroy');

        $this->uso = Env::findOrFail($usoId);
    }

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

    /**
     * A qué afectaría.
     *
     * **En vivo, no con un `withCount` del `mount()`.** Livewire rehidrata el modelo desde
     * su id en cada petición y los atributos agregados no sobreviven al snapshot: volverían
     * como 0 y el bloqueo se saltaría solo al confirmar. Es el fallo que se cazó en
     * `TypeDeleteModal` antes de salir.
     *
     * Los entornos cuentan **todos, activos o no**: un entorno apagado se puede volver a
     * encender, y entonces su uso tendría que seguir existiendo.
     *
     * @return array{entornos: int, clientes: int, activos: int}
     */
    public function impacto(): array
    {
        return [
            'entornos' => $this->uso->environments()->count(),
            'activos' => $this->uso->environments()->where('active', true)->count(),
            'clientes' => $this->uso->environments()->distinct()->count('client_id'),
        ];
    }

    /** ¿Lo declara algún entorno, o es la fila protegida? Entonces no se borra. */
    public function estaBloqueado(): bool
    {
        return $this->uso->esExentoDelIndice() || $this->impacto()['entornos'] > 0;
    }

    public function borrar(): void
    {
        $this->authorize('admin.configurations.envs.destroy');

        // Se vuelve a comprobar: esconder el botón no es protegerlo (MGR-005), y entre
        // abrir la modal y confirmar alguien puede haber creado un entorno con este uso.
        //
        // **Y la modal no se cierra.** Cerrándola, el aviso iría por `session()->flash()` y
        // la pantalla de detrás no se vuelve a pintar —no hay evento que la despierte—, así
        // que el mensaje no llegaría a ninguna parte: se vería cerrarse la modal y el uso
        // seguir ahí, sin explicación. Dejándola abierta, `render()` recalcula el bloqueo y
        // la propia modal pasa a la variante que dice cuántos entornos son.
        if ($this->estaBloqueado()) {
            return;
        }

        $nombre = $this->uso->name;
        $shortname = $this->uso->shortname;
        $id = $this->uso->id;

        // Lógico: `Env` usa `SoftDeletes`, así que un uso borrado por error se recupera y
        // los entornos que lo tengan guardado en su columna `env` lo vuelven a emparejar.
        $this->uso->delete();

        MonitoringLog::db(
            'warning',
            '16039',
            'Uso de entorno borrado del catálogo: ' . $nombre . ' (' . $shortname . ')'
            . ' — sin entornos que lo declararan'
            . ' (por ' . (Auth::user()?->name ?? 'desconocido') . ')',
            'Env',
            (string) $id
        );

        session()->flash('success', '«' . $nombre . '» ya no está en el catálogo de usos. '
            . 'El borrado es lógico: un administrador puede recuperarlo. Ojo: si algún Moodle '
            . 'sigue mandando «' . $shortname . '» en su sync, su petición se rechazará hasta '
            . 'que se corrija su configuración o se recupere el uso.');

        // Clave numérica: el paquete hace `[$event, $params] = $event` cuando el valor es
        // un array, así que `['evento' => []]` revienta con "Undefined array key 0".
        $this->closeModalWithEvents(['usosCambiados']);
    }

    public function render()
    {
        return view('livewire.configurations.envs.borrar-uso-modal', [
            'impacto' => $this->impacto(),
            'bloqueado' => $this->estaBloqueado(),
            'esProtegido' => $this->uso->esExentoDelIndice(),
        ]);
    }
}
