<?php

namespace App\Livewire\Environments\Components;

use App\Models\Clients\Client;
use App\Models\Environments\Environment;
use App\Services\Moodle\MoodleSyncService;
use Livewire\Component;

class EnvironmentCard extends Component
{
    public Environment $environment;
    /**
     * **Nulable a propósito.** El listado pasa `$environment->client`, y `Client` usa
     * SoftDeletes: con un cliente borrado esa relación es null y el tipo estricto
     * lanzaba un TypeError que **tumbaba el listado de entornos entero**, no solo esa
     * tarjeta. Las cascadas del esquema no ayudan porque no se disparan con un borrado
     * en blando.
     */
    public ?Client $client = null;
    public $showClient;

    protected $listeners = [
        'environmentDisassociated' => 'handleDisassociateEnvironment',
    ];

    public function mount(Environment $environment, ?Client $client = null, bool $showClient = false)
    {
        $this->environment = $environment;
        $this->client = $client;
        $this->showClient = $showClient;
    }

    public function openDisassociateModal()
    {
        $this->dispatch('openModal',
            component: \App\Livewire\Components\ConfirmModal::class,
            arguments: [
                'itemId' => $this->environment->id,
                'itemName' => $this->environment->name,
                'title' => 'Desasociar entorno',
                'message' => '¿Estás seguro de que deseas desasociar el entorno? El entorno perderá acceso a los productos asociados.',
                'confirmText' => 'Desasociar',
                'cancelText' => 'Cancelar',
                'eventName' => 'environmentDisassociated',
                'context' => 'environment',
                'confirmButtonColor' => 'orange',
            ]
        );
    }

    public function handleDisassociateEnvironment($data)
    {
        $environmentId = $data['itemId'] ?? $data;
        
        // Verificar que el entorno sea el correcto
        if ($this->environment->id != $environmentId) {
            session()->flash('error', 'Error: El entorno no coincide.');
            return;
        }

        // El permiso de la ruta no se reaplica en /livewire/update. Ver known-issues MGR-005.
        $this->authorize('admin.license-tokens.manage-environments');

        try {
            $domain = $this->environment->domain;

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

            // Desasociar deja el sitio SIN licencia: su plugin empezará a recibir
            // "Environment not found". Decirlo, en vez de solo "correctamente".
            session()->flash('success', 'Entorno desasociado. Atención: ' . $domain
                . ' se queda sin token y dejará de recibir licencia.');
        } catch (\Exception $e) {
            session()->flash('error', 'Error al desasociar el entorno.');
        }
    }

    /**
     * ¿Se le puede pedir a este Moodle que se sincronice?
     *
     * Hacen falta las dos cosas: permiso —el `admin.environments.refresh` que ya
     * existía en el seeder sin usarse en ninguna pantalla— y que el sitio nos haya
     * dado su token de servicios web. Sin token no hay forma de llamarle, y es más
     * honesto no ofrecer el botón que ofrecerlo y fallar.
     */
    public function getPuedeSincronizarProperty(): bool
    {
        return auth()->user()?->can('admin.environments.refresh')
            && trim((string) $this->environment->moodletoken) !== '';
    }

    /**
     * Abre la pantalla de conexión con el Moodle (token de servicios web y prueba).
     *
     * Es la salida al huevo y la gallina del alta: el Manager necesita el token para
     * pedir la sincronización, y el token llegaba solo dentro del primer `sync`, que
     * el plugin manda una vez al día.
     */
    public function abrirConexionMoodle(): void
    {
        $this->authorize('admin.environments.edit');

        $this->dispatch('openModal',
            component: \App\Livewire\Environments\MoodleConnectionModal::class,
            arguments: ['environmentId' => $this->environment->id]
        );
    }

    /**
     * Abre la pantalla de apagar/encender el entorno.
     *
     * **Va aquí y no en el formulario de edición a propósito.** Apagar un entorno hace
     * que su Moodle reciba `403 Entorno inactivo` en todas las acciones desde la
     * siguiente petición, y eso no puede pasar por desmarcar una casilla entre el nombre
     * y el dominio. Es la misma decisión que la baja de un cliente: dos caminos al mismo
     * estado, uno con consecuencias y otro silencioso, hace que se use el silencioso.
     */
    public function abrirCambioDeEstado(): void
    {
        $this->authorize('admin.environments.edit');

        $this->dispatch('openModal',
            component: \App\Livewire\Environments\EnvironmentStatusModal::class,
            arguments: ['environmentId' => $this->environment->id]
        );
    }

    /** La modal avisa al apagar o encender, para que la tarjeta se repinte. */
    #[\Livewire\Attributes\On('environmentStatusChanged')]
    public function refrescarTrasCambioDeEstado(): void
    {
        $this->environment->refresh();
    }

    /**
     * Abre la observación del entorno: anotar qué hay que revisar, o darlo por revisado.
     *
     * **Permiso propio y no `edit`.** Soporte no tiene `edit` y es justo quien detecta
     * estas cosas: colgarlo de ahí dejaba la función sin la gente que la necesita. Y
     * abrirles `edit` sería peor, porque ese permiso cambia el dominio y la licencia.
     */
    public function abrirRevision(): void
    {
        $this->authorize('admin.environments.review');

        $this->dispatch('openModal',
            component: \App\Livewire\Environments\RevisionModal::class,
            arguments: ['environmentId' => $this->environment->id]
        );
    }

    /** La modal avisa al anotar o resolver, para que la tarjeta se repinte. */
    #[\Livewire\Attributes\On('environmentReviewChanged')]
    public function refrescarTrasRevision(): void
    {
        $this->environment->refresh();
    }

    /**
     * La modal avisa cuando ha sincronizado, para que la tarjeta muestre la hora nueva.
     */
    #[\Livewire\Attributes\On('environmentSynced')]
    public function refrescarTrasSincronizar(): void
    {
        $this->environment->refresh();
    }

    public function sincronizar(MoodleSyncService $servicio): void
    {
        // El permiso de la ruta no se reaplica en /livewire/update. Ver known-issues
        // MGR-005: sin esta línea el método sería alcanzable por cualquier usuario
        // autenticado.
        $this->authorize('admin.environments.refresh');

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

        if (!$resultado['ok']) {
            // En MODAL y no en un flash. Un banner arriba de una lista larga de
            // tarjetas se pierde, y el fallo trae un detalle técnico que hay que poder
            // leer y copiar. Pasó de verdad: un fallo por certificado se veía igual
            // que si el botón no hiciera nada.
            $this->dispatch('openModal',
                component: \App\Livewire\Environments\SyncResultModal::class,
                arguments: [
                    'dominio' => (string) $this->environment->domain,
                    'mensaje' => $resultado['mensaje'],
                    'detalle' => $resultado['detalle'] ?? null,
                ]
            );

            return;
        }

        // El Moodle nos ha llamado de vuelta mientras esperábamos, así que la fila ya
        // está actualizada: se recarga para que la tarjeta muestre la hora nueva y no
        // la de antes de pulsar.
        $this->environment->refresh();

        session()->flash('success', $resultado['mensaje']);
    }

    public function render()
    {
        return view('livewire.environments.components.environment-card');
    }
}

