<?php

namespace App\Livewire\Configurations\Envs;

use App\Models\Environments\Env;
use App\Models\Monitoring\Log as MonitoringLog;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\Rule;
use Livewire\Component;

/**
 * Editar un uso del entorno.
 *
 * ## El `shortname` se queda fijo cuando hay entornos usándolo
 *
 * **No es prudencia: es que cambiarlo no renombra nada.** `environments.env` guarda la
 * cadena, no una clave ajena —el valor lo manda cada Moodle en el payload—, así que
 * renombrar `pro` a `produccion` dejaría veinte entornos con un `env` que el catálogo ya no
 * reconoce: el filtro no los encontraría, su etiqueta saldría en gris y su formulario no
 * podría guardarlos sin cambiarles el uso. Y el `sync` siguiente los volvería a poner en
 * `pro`, que ya no existe.
 *
 * Con cero entornos sí se puede cambiar: ahí no hay nada que quede descolgado.
 *
 * ## Y `local` no se renombra nunca
 *
 * `environments.domain_unique` es una columna generada que compara `env` con la **cadena
 * literal** `'local'`, y de ella cuelga el índice único del dominio: los sitios locales
 * están exentos porque varios desarrolladores comparten `moodle.test`. Renombrarlo dejaría
 * a los locales nuevos sin la exención, con un error de clave duplicada que no menciona
 * `env` en ninguna parte. Ver {@see Env::esExentoDelIndice()}.
 */
class Edit extends Component
{
    public Env $env;

    public string $shortname = '';

    public string $name = '';

    public ?string $description = null;

    public string $color = 'verde';

    public bool $visible_por_defecto = true;

    public function mount(Env $env): void
    {
        $this->authorize('admin.configurations.envs.edit');

        $this->env = $env;
        $this->shortname = $env->shortname;
        $this->name = $env->name;
        $this->description = $env->description;
        // Si la fila lleva un par de colores que no está en la paleta, se deja el primero
        // marcado pero la vista lo dice: cambiárselo en silencio al guardar sería peor.
        $this->color = $env->claveDePaleta() ?? array_key_first(Env::PALETA);
        $this->visible_por_defecto = $env->visible_por_defecto;
    }

    /** ¿Se puede tocar el `shortname`? Ver el docblock de la clase. */
    public function shortnameEsFijo(): bool
    {
        return $this->env->esExentoDelIndice() || $this->cuantosEntornos() > 0;
    }

    /**
     * Cuántos entornos declaran este uso.
     *
     * En vivo y no con un `withCount` del `mount()`: los agregados **no sobreviven al
     * snapshot de Livewire**, así que volverían como 0 al guardar y el bloqueo del
     * `shortname` se saltaría solo. Es el mismo fallo que se cazó en `TypeDeleteModal`.
     */
    public function cuantosEntornos(): int
    {
        return $this->env->cuantosEntornos();
    }

    protected function rules(): array
    {
        return [
            'shortname' => ['required', 'string', 'max:20', 'regex:/^[a-z0-9_-]+$/',
                Rule::unique('envs', 'shortname')->ignore($this->env->id)],
            'name' => ['required', 'string', 'max:60'],
            'description' => ['nullable', 'string', 'max:1000'],
            'color' => ['required', 'string', Rule::in(array_keys(Env::PALETA))],
            'visible_por_defecto' => ['boolean'],
        ];
    }

    protected function messages(): array
    {
        return [
            'shortname.regex' => 'Solo minúsculas, números, guion y guion bajo: este valor se compara tal cual con lo que manda el plugin del cliente.',
            'shortname.unique' => 'Ese shortname ya está en el catálogo — y sigue ocupado aunque el uso que lo tenía esté borrado.',
        ];
    }

    public function update()
    {
        $this->authorize('admin.configurations.envs.edit');

        $datos = $this->validate();

        // **Se vuelve a comprobar aquí, y no basta con deshabilitar el campo en la vista:**
        // esconder un control no es protegerlo (MGR-005), y entre abrir el formulario y
        // guardar alguien puede haber dado de alta un entorno con este uso.
        if ($this->shortnameEsFijo() && $datos['shortname'] !== $this->env->shortname) {
            $this->addError('shortname', $this->env->esExentoDelIndice()
                ? 'El shortname de «local» no se puede cambiar: de esa cadena literal depende la exención del índice único del dominio, que es lo que permite que varios desarrolladores compartan el mismo dominio.'
                : 'No se puede cambiar el shortname: hay ' . $this->cuantosEntornos() . ' entorno(s) que lo tienen guardado, y cambiarlo aquí no los renombra — se quedarían con un uso que el catálogo no reconoce.');

            return null;
        }

        $paleta = Env::PALETA[$datos['color']];

        $antes = $this->env->only(['shortname', 'name', 'visible_por_defecto']);

        $this->env->update([
            'shortname' => $datos['shortname'],
            'name' => $datos['name'],
            'description' => $datos['description'],
            'color_text' => $paleta['texto'],
            'color_bg' => $paleta['fondo'],
            'visible_por_defecto' => $datos['visible_por_defecto'],
        ]);

        MonitoringLog::db(
            'info',
            '16038',
            'Uso de entorno modificado: ' . $this->env->name . ' (' . $this->env->shortname . ')'
            . ($antes['visible_por_defecto'] !== $this->env->visible_por_defecto
                ? ($this->env->visible_por_defecto
                    ? ' — ahora sale marcado en el filtro del listado'
                    : ' — ahora NO sale marcado en el filtro del listado')
                : '')
            . ' (por ' . (Auth::user()?->name ?? 'desconocido') . ')',
            'Env',
            (string) $this->env->id
        );

        session()->flash('success', 'Uso «' . $this->env->name . '» guardado.');

        return $this->redirect(route('configurations.catalogs'), navigate: true);
    }

    public function render()
    {
        return view('livewire.configurations.envs.form', [
            'paleta' => Env::PALETA,
            'editando' => $this->env,
            'shortnameFijo' => $this->shortnameEsFijo(),
            'cuantosEntornos' => $this->cuantosEntornos(),
        ])->layout('layouts.clean');
    }
}
