<?php

namespace App\Support;

use App\Models\Environments\Plugin;
use App\Models\Products\OwnPlugin;
use App\Models\Products\PluginFicha;
use App\Models\Products\Product;

/**
 * A qué familia pertenece un plugin: producto, nuestro, estándar de Moodle, terceros o sin
 * clasificar.
 *
 * **Una sola regla para todo el panel**: la ficha de un plugin y el filtro del inventario
 * leen esto, para que un plugin no salga «terceros» en un sitio y «sin clasificar» en otro.
 *
 * El orden es el de quién sabe más:
 *
 * 1. **Producto**: su `component` es el `slug` de un producto del catálogo.
 * 2. **Nuestro**: está en el catálogo de plugins propios.
 * 3. **Lo fijado a mano en la ficha** (`PluginFicha`): para cuando el inventario no lo sabe.
 * 4. **Lo que dice el Moodle de cada sitio** (`plugins.isstandard`, desde el 2026-10-01). Si
 *    unos dicen que sí y otros que no —salió del paquete en alguna versión—, cuenta como
 *    estándar: lo es en alguna versión del parque.
 * 5. **Sin clasificar**: nadie lo ha dicho.
 */
class FamiliaDePlugin
{
    public const PRODUCTO = 'producto';

    public const NUESTRO = 'nuestro';

    public const ESTANDAR = 'estandar';

    public const TERCEROS = 'terceros';

    public const SIN_CLASIFICAR = 'sinclas';

    /** Las que ofrece el filtro del inventario, con «nuestros» juntando producto y nuestro. */
    public const DEL_FILTRO = ['nuestros', self::ESTANDAR, self::TERCEROS, self::SIN_CLASIFICAR];

    /**
     * La familia de varios componentes a la vez: **cuatro consultas en total**, no una por
     * componente. Es lo que necesita el inventario, con quinientas filas.
     *
     * @param  iterable<string>  $components
     * @return array<string, string> component => familia
     */
    public static function de(iterable $components): array
    {
        $components = collect($components)->filter()->unique()->values();

        if ($components->isEmpty()) {
            return [];
        }

        $productos = array_flip(Product::query()->whereIn('slug', $components)->pluck('slug')->all());
        $propios = array_flip(OwnPlugin::query()->whereIn('component', $components)->pluck('component')->all());
        $fijadas = PluginFicha::query()->whereIn('component', $components)->whereNotNull('clasificacion')
            ->pluck('clasificacion', 'component')->all();

        // Cuántos sitios dicen que sí y cuántos que no, por componente, en una consulta.
        $segunLosSitios = Plugin::query()
            ->whereIn('component', $components)
            ->whereNotNull('isstandard')
            ->selectRaw('component, sum(case when isstandard then 1 else 0 end) as si, sum(case when isstandard then 0 else 1 end) as no')
            ->groupBy('component')
            ->get()
            ->keyBy('component');

        return $components->mapWithKeys(function (string $component) use ($productos, $propios, $fijadas, $segunLosSitios) {
            $sitios = $segunLosSitios->get($component);

            $familia = match (true) {
                isset($productos[$component]) => self::PRODUCTO,
                isset($propios[$component]) => self::NUESTRO,
                isset($fijadas[$component]) && in_array($fijadas[$component], PluginFicha::CLASIFICACIONES, true) => $fijadas[$component],
                $sitios !== null && (int) $sitios->si > 0 => self::ESTANDAR,
                $sitios !== null && (int) $sitios->no > 0 => self::TERCEROS,
                default => self::SIN_CLASIFICAR,
            };

            return [$component => $familia];
        })->all();
    }

    public static function para(string $component): string
    {
        return self::de([$component])[$component] ?? self::SIN_CLASIFICAR;
    }

    /** ¿Esta familia entra en lo que el filtro del inventario llama así? */
    public static function encaja(string $familia, string $filtro): bool
    {
        return $filtro === 'nuestros'
            ? in_array($familia, [self::PRODUCTO, self::NUESTRO], true)
            : $familia === $filtro;
    }
}
