<?php

namespace App\Livewire\Environments;

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

/**
 * Anotar que un entorno está pendiente de revisar, o dar la anotación por resuelta.
 *
 * **La pregunta que no tenía sitio.** Alguien ve que un entorno está mal —un plugin
 * desalineado, un dominio que va a cambiar, algo que pidió el cliente— y no había dónde
 * escribirlo: se quedaba en su cabeza o en un chat. El panel sabía muchas cosas del parque y
 * ninguna la había escrito una persona.
 *
 * ## El nivel es obligatorio, y por qué
 *
 * Porque una lista de pendientes sin orden es una lista que no se mira. Los tres niveles
 * llevan escrito **cuándo se usa cada uno** ({@see RevisionDeEntorno::NIVELES}): sin ese
 * criterio, el nivel se elige por cómo de enfadado está quien anota y a la semana todo es
 * urgente.
 *
 * ## Permiso propio: `admin.environments.review`
 *
 * Y no `admin.environments.edit`, que era lo cómodo. **Soporte no tiene `edit`** y Soporte es
 * justo quien detecta estas cosas: colgarlo de ahí dejaba la función sin la gente que la
 * necesita. Y darles `edit` sería peor —ese permiso cambia el dominio, la licencia y el tipo
 * del entorno—. Anotar no es configurar.
 *
 * ## Lo que se borra queda escrito
 *
 * Al dar por revisada una observación se limpian las cuatro columnas: dejar la nota de algo
 * resuelto haría que el listado siguiera enseñando «pendiente». El texto, el nivel y quién la
 * cerró quedan en Acciones del panel (16043 / 16044), que es donde se consulta el histórico
 * de todo lo demás.
 */
class RevisionModal extends ModalComponent
{
    public Environment $environment;

    /** Qué hay que mirar. Es lo único de este entorno que escribe un humano. */
    public string $nota = '';

    /** `aviso`, `importante` o `urgente`. */
    public string $nivel = RevisionDeEntorno::AVISO;

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

        // Por id y con `findOrFail`: el id llega en el snapshot de Livewire, así que la
        // consulta es el único sitio donde se puede acotar. Ver MGR-006.
        $this->environment = Environment::with(['client', 'reviewFlaggedBy'])->findOrFail($environmentId);

        // Editando una observación que ya existe se parte de lo que hay, no de un
        // formulario en blanco: vaciarlo obligaría a reescribir para cambiar el nivel.
        $this->nota = (string) $this->environment->review_note;
        $this->nivel = $this->environment->review_level ?? RevisionDeEntorno::AVISO;
    }

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

    protected function rules(): array
    {
        return [
            // Con mínimo: «revisar» no dice nada dentro de tres semanas, y quien lo lea
            // tendrá que preguntar a quien lo escribió. Ese es el fallo que hay que evitar.
            'nota' => 'required|string|min:10|max:2000',
            'nivel' => RevisionDeEntorno::regla(),
        ];
    }

    protected function messages(): array
    {
        return [
            'nota.required' => 'Escribe qué hay que revisar: sin eso, la marca no sirve de nada.',
            'nota.min' => 'Un poco más de detalle. Dentro de tres semanas «revisar» no dirá nada.',
        ];
    }

    /** ¿Se está editando una observación que ya existía? */
    public function yaEstaba(): bool
    {
        return $this->environment->estaPendienteDeRevision();
    }

    public function guardar(): void
    {
        $this->authorize('admin.environments.review');

        $datos = $this->validate();
        $era = $this->yaEstaba();

        $this->environment->marcarParaRevisar($datos['nota'], $datos['nivel'], Auth::id());

        MonitoringLog::db(
            $datos['nivel'] === RevisionDeEntorno::URGENTE ? 'danger' : 'warning',
            '16043',
            ($era ? 'Observación modificada' : 'Entorno marcado para revisar')
                . ' en ' . $this->environment->name
                . ' [' . RevisionDeEntorno::etiqueta($datos['nivel']) . ']: ' . $datos['nota'],
            'Environment',
            (string) $this->environment->id
        );

        Environment::olvidarElParque();

        $this->closeModal();
        $this->dispatch('environmentReviewChanged');

        session()->flash('success', $era
            ? 'Observación actualizada.'
            : $this->environment->name . ' queda marcado como pendiente de revisar.');
    }

    public function resolver(): void
    {
        $this->authorize('admin.environments.review');

        if (! $this->yaEstaba()) {
            return;
        }

        // **El texto se lee ANTES de borrarlo**: el apunte del log es lo único que queda de
        // esta observación, y sin el texto diría que alguien resolvió algo sin decir qué.
        $nota = (string) $this->environment->review_note;
        $nivel = (string) $this->environment->review_level;

        $this->environment->darPorRevisado();

        MonitoringLog::db(
            'info',
            '16044',
            'Observación resuelta en ' . $this->environment->name
                . ' [' . RevisionDeEntorno::etiqueta($nivel) . ']: ' . $nota,
            'Environment',
            (string) $this->environment->id
        );

        Environment::olvidarElParque();

        $this->closeModal();
        $this->dispatch('environmentReviewChanged');

        session()->flash('success', 'Observación resuelta. Queda en Acciones del panel por si hace falta.');
    }

    public function render()
    {
        return view('livewire.environments.revision-modal', [
            'niveles' => RevisionDeEntorno::NIVELES,
            'yaEstaba' => $this->yaEstaba(),
        ]);
    }
}
