<?php

namespace App\Livewire\Scss;

use App\Models\Products\Product;
use App\Models\Scss\ScssFile;
use App\Models\Scss\ScssVersion;
use App\Services\Scss\ScssStorageService;
use App\Support\RevisionDeCodigo;
use Livewire\Component;

class Edit extends Component
{
    public Product $product;
    public ScssVersion $scssVersion;
    public ScssFile $scssFile;
    public string $filename = '';
    public string $content = '';
    public ?string $scssValidationError = null;
    public bool $scssValid = true;

    /**
     * Lo que ha encontrado la revisión del archivo.
     *
     * Ver {@see \App\Support\RevisionDeCodigo}: no compila nada —no hay compilador de
     * SASS ni motor de JavaScript en el servidor— pero mira lo que se puede mirar
     * leyendo el texto, que es lo que más veces rompe un archivo: algo sin cerrar, y un
     * `@import` que apunta a un archivo que no está en esta versión.
     *
     * @var array<int, array{tipo: string, mensaje: string, linea: ?int}>
     */
    public array $revision = [];

    public function mount(Product $product, ScssVersion $scssVersion, ScssFile $scssFile)
    {
        $this->product = $product;
        $this->scssVersion = $scssVersion;
        $this->scssFile = $scssFile->load(['scssVersion.product', 'creator', 'updater']);
        $this->filename = $scssFile->filename;
        $this->content = $scssFile->content;
    }

    /**
     * Revisa el archivo y deja el resultado en $revision.
     *
     * **Antes esto solo miraba si el contenido estaba vacío** y después la pantalla
     * pintaba «SCSS válido» en verde: un archivo con una llave sin cerrar pasaba con el
     * visto bueno puesto. Ahora se revisa lo que se puede revisar sin compilar, y el
     * resto lo marca el editor mientras se escribe.
     */
    public function validateScss()
    {
        $this->scssValidationError = null;
        $this->scssValid = true;
        $this->revision = [];

        // El archivo vacío entra en la misma lista que lo demás: si hay dos sitios
        // donde mirar lo que va mal, se mira uno.
        if (empty(trim($this->content))) {
            $this->scssValidationError = 'El archivo está vacío.';
            $this->scssValid = false;
            $this->revision = [[
                'tipo' => 'error',
                'mensaje' => 'El archivo está vacío: no hay nada que servirle al cliente.',
                'linea' => null,
            ]];

            return;
        }

        $this->revision = RevisionDeCodigo::revisar(
            $this->content,
            RevisionDeCodigo::SCSS,
            $this->hermanos()
        );

        $this->scssValid = ! RevisionDeCodigo::hayErrores($this->revision);

        if (! $this->scssValid) {
            $this->scssValidationError = 'El archivo tiene errores que impiden guardarlo.';
        }
    }

    /**
     * Los otros archivos de esta versión, para resolver los `@import`.
     *
     * Se excluye el que se está editando: importarse a sí mismo no es un caso que haya
     * que dar por bueno.
     *
     * @return array<int, string>
     */
    private function hermanos(): array
    {
        return ScssFile::where('scss_version_id', $this->scssFile->scss_version_id)
            ->where('id', '!=', $this->scssFile->id)
            ->pluck('filename')
            ->all();
    }

    public function save()
    {
        $this->authorize('admin.scss.file.edit');
        
        // Validar SCSS antes de guardar
        $this->validateScss();

        if (!$this->scssValid) {
            $this->addError('content', $this->scssValidationError ?? 'SCSS inválido');
            return;
        }

        // Validar que el nombre del archivo no haya cambiado o que no exista otro con ese nombre
        if ($this->filename !== $this->scssFile->filename) {
            $exists = ScssFile::where('scss_version_id', $this->scssFile->scss_version_id)
                ->where('filename', $this->filename)
                ->where('id', '!=', $this->scssFile->id)
                ->exists();

            if ($exists) {
                $this->addError('filename', 'Ya existe un archivo con este nombre para esta versión.');
                return;
            }

            // Si cambió el nombre, eliminar el archivo físico antiguo
            ScssStorageService::deleteFile(
                $this->product,
                $this->scssFile->scssVersion,
                $this->scssFile->filename
            );
        }

        // Actualizar en BD
        $this->scssFile->update([
            'filename' => $this->filename,
            'content' => $this->content,
            'updated_by' => auth()->id(),
        ]);

        // Actualizar archivo físico en storage
        $saved = ScssStorageService::saveFile(
            $this->product,
            $this->scssFile->scssVersion,
            $this->filename,
            $this->content
        );

        if (!$saved) {
            $this->addError('content', 'Error al guardar el archivo físico.');
            return;
        }

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

        return $this->redirect(route('products.scss.file.show', [$this->product, $this->scssVersion, $this->scssFile]), navigate: true);
    }

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