<?php

namespace App\Livewire\Configurations\Environments;

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

/**
 * Borrar un tipo de entorno del catálogo.
 *
 * **Lo que había: nada.** La línea del botón estaba **comentada** en el blade y apuntaba
 * a `configurations.environments.destroy`, una ruta que no existe en ningún sitio; el
 * permiso `...environments-types.destroy` tampoco existía. Cuarta vez que aparece este
 * patrón en el release —MGR-039, MGR-045, MGR-060 y esto—.
 *
 * **Y no se borra si algún entorno lo declara.** El tipo es la plataforma que dice un
 * sitio —Moodle LMS, Workplace, WordPress, Goodle—, y de ella depende **qué productos son
 * compatibles**: la relación `product_type` empareja producto con tipo, y
 * `findCompatibleVersion()` la usa para decidir qué versión servir. Un entorno cuyo tipo
 * desaparece deja de emparejar con nada:
 *
 * 1. `environments.type_id` sigue apuntando a la fila borrada en blando.
 * 2. `$environment->type` devuelve `null`, porque `Type` usa `SoftDeletes`.
 * 3. El emparejamiento de productos compatibles se queda sin lado derecho.
 * 4. Y la ficha del entorno pinta el tipo vacío, sin decir por qué.
 *
 * O sea que borrar un tipo en uso **no da un error**: deja entornos que no saben qué son.
 * Por eso se bloquea en lugar de avisar. Es la misma regla que en el borrado de productos.
 *
 * Hoy los cuatro tipos tienen entornos, así que en producción lo que se ve es el candado.
 * Eso es correcto: la pantalla explica por qué y qué hacer antes.
 */
class TypeDeleteModal extends ModalComponent
{
    public Type $type;

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

        // Sin `withCount`: los agregados no sobreviven al snapshot de Livewire, así que
        // `impacto()` los consulta en vivo. Tenerlos aquí solo daba una falsa sensación
        // de que el dato viaja.
        $this->type = Type::findOrFail($typeId);
    }

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

    /**
     * A qué afectaría.
     *
     * **Se consulta en vivo, no con el `withCount` del `mount()`.** Livewire rehidrata el
     * modelo en cada petición desde su id, y los atributos agregados **no sobreviven al
     * snapshot**: `environments_count` volvía como `null`, o sea 0, y `estaEnUso()`
     * devolvía `false` al confirmar. El bloqueo se saltaba solo, sin que nadie hiciera
     * nada raro —lo cogió el test antes de salir—.
     *
     * Los entornos cuentan **todos**, activos o no: un entorno dado de baja se puede
     * reactivar, y entonces su tipo tendría que seguir existiendo.
     *
     * @return array{entornos:int, productos:int, clientes:int}
     */
    public function impacto(): array
    {
        return [
            'entornos' => $this->type->environments()->count(),
            'productos' => $this->type->products()->count(),
            'clientes' => $this->type->environments()->distinct()->count('client_id'),
        ];
    }

    /** ¿Lo declara algún entorno? Entonces no se borra. */
    public function estaEnUso(): bool
    {
        return $this->impacto()['entornos'] > 0;
    }

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

        // Se vuelve a comprobar aquí: esconder el botón no es protegerlo (MGR-005), y
        // entre abrir la modal y confirmar alguien puede haber creado un entorno de este
        // tipo.
        //
        // **Y la modal no se cierra**, aunque sea lo que pide el cuerpo. Cerrándola, el
        // aviso se manda 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 llega a
        // ninguna parte: el usuario ve cerrarse la modal y el tipo seguir ahí, sin
        // explicación. Dejándola abierta, `render()` recalcula `enUso` y la propia modal
        // pasa a la variante de bloqueo, que dice cuántos entornos son y qué hacer antes.
        if ($this->estaEnUso()) {
            return;
        }

        $nombre = $this->type->name;
        $shortname = $this->type->shortname;
        $productos = $this->impacto()['productos'];
        $id = $this->type->id;

        // Lógico siempre: `Type` usa `SoftDeletes`, así que un tipo borrado por error se
        // puede recuperar y los entornos que lo apuntaran lo recuperan con él.
        $this->type->delete();

        MonitoringLog::db(
            'warning',
            '16025',
            'Tipo de entorno borrado del catálogo: ' . $nombre . ' (' . $shortname . ')'
            . ($productos > 0
                ? ' — tenía ' . $productos . ' producto(s) declarados compatibles'
                : ' — sin productos compatibles declarados')
            . ' (por ' . (Auth::user()?->name ?? 'desconocido') . ')',
            'Type',
            (string) $id
        );

        session()->flash('success', '«' . $nombre . '» ya no está en el catálogo de plataformas. '
            . 'El borrado es lógico: un administrador puede recuperarlo.');

        // 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(['typesChanged']);
    }

    public function render()
    {
        return view('livewire.configurations.environments.type-delete-modal', [
            'impacto' => $this->impacto(),
            'enUso' => $this->estaEnUso(),
        ]);
    }
}
