<?php

namespace App\Livewire\Environments;

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

/**
 * Conexión con el Moodle del cliente: poner su token de servicios web y probarla.
 *
 * **El hueco que tapa.** El Manager ya sabe pedirle a un Moodle que se sincronice
 * (`MoodleSyncService`: Manager → Moodle → Manager), pero necesita el token de servicios
 * web de ese sitio, y ese token **solo llegaba dentro del primer `sync`** que enviaba el
 * plugin. Como el plugin sincroniza con su tarea programada —una vez al día, sobre la
 * 01:00—, en un alta nueva pasaba esto:
 *
 *   1. Se da de alta cliente, entorno y licencia.
 *   2. Se instala el plugin y se pega la licencia.
 *   3. La licencia se valida al momento (el plugin llama a `products` al abrir su
 *      pantalla), pero en el Manager **no hay plugins ni datos**.
 *   4. Y el botón «Sincronizar ahora» **no aparece**, porque no hay token todavía.
 *
 * O sea: huevo y gallina justo el día del alta, y la única salida era esperar a la
 * madrugada o entrar al Moodle del cliente a lanzar la tarea a mano.
 *
 * Con esto, quien da de alta pega el token una vez y ya puede traer los datos en el
 * momento.
 *
 * **El token NO se muestra nunca.** Es una credencial de administración del Moodle de un
 * tercero —por eso se cifró en reposo, MGR-038—, así que el formulario es de solo
 * escritura: se dice si hay uno guardado y desde cuándo, y se puede reemplazar o borrar,
 * pero no leer. Un campo que lo pinte de vuelta lo expone en cada pantallazo, en el HTML
 * y en el historial del navegador.
 */
class MoodleConnectionModal extends ModalComponent
{
    public Environment $environment;

    /** Token nuevo. Solo escritura: nunca se rellena con el guardado. */
    public string $token = '';

    public ?string $resultado = null;
    public ?string $detalle = null;
    public bool $ok = false;

    public function mount(int $environmentId): void
    {
        // El permiso de la ruta no se reaplica en /livewire/update (MGR-005), y aquí
        // además se maneja una credencial ajena.
        $this->authorize('admin.environments.edit');

        $this->environment = Environment::findOrFail($environmentId);
    }

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

    /**
     * Un método normal y no una propiedad computada: la forma `getXProperty()` que usa
     * el resto del proyecto es de Livewire 2 y **no resuelve al llamarla desde dentro
     * del componente** —devolvía false con el token recién guardado, y la prueba de
     * conexión decía "no hay ningún token" justo después de guardarlo—.
     */
    public function tieneToken(): bool
    {
        return trim((string) $this->environment->moodletoken) !== '';
    }

    /**
     * Guarda el token y prueba la conexión de una vez.
     *
     * Van juntos a propósito: un token guardado y sin probar no dice nada, y el error
     * que interesa —servicios web apagados, usuario sin autorizar, token caducado— solo
     * aparece al usarlo.
     */
    public function guardarYProbar(MoodleSyncService $servicio): void
    {
        $this->authorize('admin.environments.edit');

        $datos = $this->validate([
            // Los tokens de Moodle son 32 caracteres hexadecimales. Validarlo aquí
            // ahorra un viaje al Moodle del cliente para descubrir que se ha pegado
            // media cadena o el token de otra cosa.
            'token' => ['required', 'string', 'size:32', 'regex:/^[a-f0-9]{32}$/i'],
        ], [
            'token.size' => 'Un token de Moodle tiene 32 caracteres; este tiene :size.',
            'token.regex' => 'Un token de Moodle son 32 caracteres hexadecimales (0-9, a-f).',
        ], ['token' => 'token de servicios web']);

        $anterior = $this->tieneToken();

        $this->environment->update(['moodletoken' => strtolower(trim($datos['token']))]);

        MonitoringLog::db(
            'warning',
            '16017',
            ($anterior ? 'Reemplazado' : 'Guardado') . ' el token de servicios web de '
            . $this->environment->name . ' (' . $this->environment->domain . ')'
            . ' por ' . (Auth::user()?->name ?? 'desconocido'),
            'Environment',
            (string) $this->environment->id
        );

        // El token en claro no se queda en el estado del componente: viaja en cada
        // petición de Livewire mientras esté ahí.
        $this->token = '';

        $this->probar($servicio);
    }

    public function probar(MoodleSyncService $servicio): void
    {
        $this->authorize('admin.environments.refresh');

        if (!$this->tieneToken()) {
            $this->ok = false;
            $this->resultado = 'No hay ningún token guardado todavía.';
            $this->detalle = null;

            return;
        }

        $respuesta = $servicio->lanzar($this->environment);

        $this->ok = $respuesta['ok'];
        $this->resultado = $respuesta['mensaje'];
        $this->detalle = $respuesta['detalle'] ?? null;

        // El Moodle nos ha llamado de vuelta mientras esperábamos, así que la fila ya
        // tiene la hora nueva.
        $this->environment->refresh();

        if ($this->ok) {
            $this->dispatch('environmentSynced');
        }
    }

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

        $this->environment->update(['moodletoken' => null]);

        MonitoringLog::db(
            'warning',
            '16017',
            'Borrado el token de servicios web de ' . $this->environment->name
            . ' por ' . (Auth::user()?->name ?? 'desconocido'),
            'Environment',
            (string) $this->environment->id
        );

        $this->ok = false;
        $this->resultado = 'Token borrado. El Manager ya no puede pedirle una sincronización a este sitio.';
        $this->detalle = null;
    }

    public function render()
    {
        return view('livewire.environments.moodle-connection-modal');
    }
}
