<?php

namespace App\Livewire\Traits;

use App\Support\PeticionesDeContenido;
use App\Support\RepartoDeVersiones;
use App\Support\TiposDeContenido;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;

/**
 * La pantalla de una versión de archivos: SCSS y JS.
 *
 * **Eran dos vistas idénticas de 160 líneas** —diff de 48 líneas, todas nombres— más dos
 * componentes gemelos. Lo que cambia entre las dos lo declara cada uno en su `fichaDeLaVersion()`.
 *
 * Y traen dos cosas que la pantalla no decía:
 *
 * 1. **Si esta versión se está sirviendo, y a quién.** Es la misma pregunta que resolvió el
 *    listado, y aquí falta igual: se puede estar editando una versión que no le llega a
 *    nadie sin saberlo.
 * 2. **El peso de cada archivo sin cargarlo.** La vista hacía `strlen($file->content)`, así
 *    que para pintar la columna «tamaño» se traía **el SCSS entero de todos los
 *    archivos** a memoria. Con 9 archivos de 34 KB no se nota; con un bundle grande, sí. Y
 *    el `mount()` los cargaba una vez con `load('files')` y el `render()` los volvía a
 *    consultar: dos veces lo mismo.
 */
trait MuestraVersionDeArchivos
{
    use BorraVersionesDeContenido;

    /**
     * Qué versión es esta y con qué rutas se trabaja.
     *
     * @return array{
     *     clave: string,
     *     version: Model,
     *     elemento: string,
     *     elementos: string,
     *     rutaListado: string,
     *     rutaEditarVersion: string,
     *     rutaVerArchivo: string,
     *     rutaEditarArchivo: string,
     *     rutaSubir: string,
     *     rutaCrearArchivo: string,
     *     permisoVersion: string,
     *     permisoArchivo: string
     * }
     */
    abstract protected function fichaDeLaVersion(): array;

    /** La relación de archivos de esta versión, ya acotada. */
    abstract protected function archivosDeLaVersion();

    /**
     * Los archivos con su peso, **sin traerse el contenido**.
     *
     * El tamaño lo calcula la base de datos con `length(content)`: es el mismo número que
     * daba `strlen()` en la vista, sin cargar el texto entero de cada archivo para
     * contarlo.
     *
     * @return Collection<int, Model>
     */
    protected function archivos(): Collection
    {
        return $this->archivosDeLaVersion()
            ->select(['id', 'filename', 'created_by', 'created_at', 'updated_at'])
            ->selectRaw('length(content) as peso')
            ->with('creator:id,name')
            ->orderBy('filename')
            ->get();
    }

    /**
     * A qué entornos les llega esta versión.
     *
     * Se calcula sobre **todas** las versiones del producto, no sobre esta: la API sirve la
     * más alta que no supere el plugin de cada sitio, así que saber si esta le llega a
     * alguien exige mirar las demás.
     */
    protected function aQuienLlega(): array
    {
        $ficha = $this->fichaDeLaVersion();
        $modelo = $ficha['version']::class;

        $reparto = RepartoDeVersiones::reparto(
            $this->product,
            // **Solo las que se sirven.** Una versión en borrador o retirada no sale por la
            // API, así que contarla aquí diría que le está llegando a alguien: justo lo
            // contrario de lo que significa no publicarla (MGR-023).
            $modelo::where('product_id', $this->product->id)->active()->pluck('version')
        );

        return [
            'laReciben' => $reparto['porVersion'][(string) $ficha['version']->version] ?? 0,
            'entornos' => $reparto['entornos'],
            'conPlugin' => $reparto['entornos'] - $reparto['sinPlugin'],
        ];
    }

    protected function datosDeLaPantalla(): array
    {
        $ficha = $this->fichaDeLaVersion();
        $tipo = TiposDeContenido::TIPOS[$ficha['clave']] ?? [];
        [$fondo, $tinta] = TiposDeContenido::tonoDe($ficha['clave']);

        $archivos = $this->archivos();

        return [
            'product' => $this->product,
            'ficha' => array_merge($tipo, $ficha, ['fondo' => $fondo, 'tinta' => $tinta]),
            'archivos' => $archivos,
            // El peso total: es lo que se compara entre versiones para ver si una creció.
            'peso' => (int) $archivos->sum('peso'),
            // Y las carpetas, que es la otra forma de leer una versión de archivos: «9
            // archivos» no dice nada, «9 en 3 carpetas» sí.
            'carpetas' => $archivos
                ->map(fn (Model $a) => str_contains((string) $a->filename, '/')
                    ? dirname((string) $a->filename)
                    : '/')
                ->unique()
                ->count(),
            'llega' => $this->aQuienLlega(),
            'peticiones' => PeticionesDeContenido::de($this->product, $tipo['accion'] ?? ''),
        ];
    }
}
