<?php

namespace App\Livewire\Setups;

use App\Services\Setups\RevisionDelSetup;
use App\Models\Products\Product;
use App\Models\Setups\Setup;
use Livewire\Component;
use Symfony\Component\Yaml\Yaml;
use Symfony\Component\Yaml\Exception\ParseException;

class Edit extends Component
{
    public Product $product;
    public Setup $setup;
    public string $yaml = '';
    public ?string $changeLog = null;
    public ?string $yamlValidationError = null;
    public bool $yamlValid = true;

    /**
     * Lo que la revisión estructural tiene que decir del setup.
     *
     * **No impide guardar.** Son avisos sobre cómo está escrito el fichero, no
     * sobre si el plugin lo va a aceptar — eso el Manager no lo sabe.
     *
     * @var array<int, string>
     */
    public array $avisosDelSetup = [];

    public function mount(Product $product, Setup $setup)
    {
        $this->product = $product;
        $this->setup = $setup->load(['product', 'creator', 'updater']);
        $this->yaml = $setup->yaml;
        $this->changeLog = null;
    }

    /**
     * ¿Alguno de los avisos es de los que se arreglan poniendo bien la cabecera?
     *
     * Se decide por el texto del aviso y no por un campo aparte porque los avisos son
     * cadenas —así los devuelve la revisión— y añadirles estructura solo para esto obligaría
     * a tocar los siete tipos de aviso que hay.
     */
    public function cabeceraDescuadrada(): bool
    {
        foreach ($this->avisosDelSetup as $aviso) {
            if (str_contains($aviso, 'La cabecera dice') || str_contains($aviso, 'de la cabecera.')) {
                return true;
            }
        }

        return false;
    }

    /**
     * Pone en la cabecera el producto y la versión de verdad.
     *
     * **Rellenarla a mano es justo lo que se olvida**, y es de lo que avisa MGR-096: el caso
     * probable es copiar un setup de otro producto o de otra versión, cambiar el formulario y
     * dejar las dos primeras líneas del fichero diciendo lo anterior.
     *
     * No se hace solo al guardar: el fichero es de quien lo escribe, y reescribirle dos
     * líneas sin pedirlo es la clase de ayuda que hace desconfiar del editor.
     */
    public function rellenarCabecera(): void
    {
        // El gate de la ruta no se reaplica en /livewire/update (MGR-005).
        $this->authorize('admin.setups.edit');

        if (trim($this->yaml) === '') {
            return;
        }

        $this->yaml = RevisionDelSetup::conLaCabeceraPuesta(
            $this->yaml,
            (string) $this->product->slug,
            (string) $this->setup->version
        );

        // Y se vuelve a revisar, para que el aviso desaparezca en el momento: dejarlo puesto
        // después de haberlo arreglado hace dudar de si el botón ha hecho algo.
        $this->validateYaml();
    }

    public function validateYaml()
    {
        $this->yamlValidationError = null;
        $this->yamlValid = true;
        $this->avisosDelSetup = [];

        if (empty(trim($this->yaml))) {
            $this->yamlValidationError = 'El YAML no puede estar vacío';
            $this->yamlValid = false;
            return;
        }

        try {
            $parsedData = Yaml::parse($this->yaml);

            if (!is_array($parsedData)) {
                $this->yamlValidationError = 'El YAML no contiene una estructura válida';
                $this->yamlValid = false;
                return;
            }

            $this->yamlValid = true;

            // **Revisión estructural, que no bloquea** (pedida el 2026-09-08). Dice si el
            // setup está **bien escrito** —claves conocidas, campos obligatorios,
            // referencias que resuelven—, y nunca si «va a funcionar»: eso solo lo sabe el
            // plugin, que es quien lo aplica. Ver `RevisionDelSetup`.
            $this->avisosDelSetup = RevisionDelSetup::revisar(
                $parsedData,
                // **El producto y la versión de la fila**, para que la revisión pueda
                // decir si la cabecera del fichero los contradice (MGR-096).
                $this->product->slug,
                (string) $this->setup->version
            )['avisos'];
        } catch (ParseException $e) {
            $this->yamlValidationError = 'Error de sintaxis YAML: ' . $e->getMessage();
            $this->yamlValid = false;
        } catch (\Exception $e) {
            $this->yamlValidationError = 'Error al procesar YAML: ' . $e->getMessage();
            $this->yamlValid = false;
        }
    }

    public function save()
    {
        $this->authorize('admin.setups.edit');
        
        // Validar YAML antes de guardar
        $this->validateYaml();

        if (!$this->yamlValid) {
            $this->addError('yaml', $this->yamlValidationError ?? 'YAML inválido');
            return;
        }

        // Crear entrada en historial antes de actualizar
        $this->setup->createHistoryEntry($this->changeLog);

        // Actualizar setup
        $this->setup->update([
            'yaml' => $this->yaml,
            'change_log' => $this->changeLog,
            'updated_by' => auth()->id(),
        ]);

        session()->flash('success', 'Setup actualizado correctamente.');

        return $this->redirect(route('products.setups.show', [$this->product, $this->setup]), navigate: true);
    }

    public function duplicate()
    {
        try {
            $newSetup = $this->setup->duplicate();
            session()->flash('success', "Setup duplicado. Nueva versión: {$newSetup->version}");

            return $this->redirect(route('products.setups.edit', [$this->product, $newSetup]), navigate: true);
        } catch (\Exception $e) {
            $this->addError('duplicate', $e->getMessage());
        }
    }

    public function render()
    {
        return view('livewire.setups.edit', [
            'product' => $this->product,
        ])->layout('layouts.clean');
    }
}

