<?php

namespace Tests\Unit;

use App\Support\ColorDeAccion;
use PHPUnit\Framework\TestCase;

/**
 * El color de cada acción de la API.
 *
 * Lo que se vigila es lo que hace que el color sirva: **que sea siempre el mismo** —si
 * cambia entre pantallas o entre recargas, el ojo deja de poder agrupar y el color pasa a
 * ser ruido— y **que no invada los tres colores que ya significan algo** en este panel:
 * rojo es error, verde es correcta y naranja es la marca. Una acción en rojo se lee como
 * una acción que ha fallado, que es justo el malentendido que el color venía a evitar.
 */
class ColorDeAccionTest extends TestCase
{
    public function test_la_misma_accion_da_siempre_el_mismo_color(): void
    {
        $primero = ColorDeAccion::de('licence');

        // Diez veces: si hubiera algo aleatorio dentro, aquí se cae.
        foreach (range(1, 10) as $ignorado) {
            $this->assertSame($primero, ColorDeAccion::de('licence'));
        }

        // Y da igual cómo llegue escrita: el visor la pinta en minúsculas y el payload
        // podría mandarla de otra forma.
        $this->assertSame($primero, ColorDeAccion::de('LICENCE'));
        $this->assertSame($primero, ColorDeAccion::de('  licence  '));
    }

    public function test_ninguna_accion_del_contrato_comparte_color_con_otra(): void
    {
        // **El test que existe por un fallo real.** La primera versión hasheaba el nombre
        // sobre la paleta, y `licence` y `products` salían del mismo color. No era mala
        // suerte: 13 acciones en 20 huecos colisionan con probabilidad del 98 %.
        //
        // Por eso las del contrato van fijadas. Si alguien vuelve a hashearlas, esto cae.
        $conocidas = ColorDeAccion::conocidas();

        $matices = array_map(fn ($a) => ColorDeAccion::matiz($a), $conocidas);

        $this->assertCount(count($conocidas), array_unique($matices),
            'dos acciones del contrato comparten color: ' . implode(', ', $conocidas));
    }

    public function test_una_accion_desconocida_no_roba_el_color_de_una_conocida(): void
    {
        // Una acción nueva del plugin tiene que tener color sin tocar código, pero no a
        // costa de que `licence` deje de ser reconocible.
        $deConocidas = array_map(fn ($a) => ColorDeAccion::matiz($a), ColorDeAccion::conocidas());

        foreach (['una-accion-nueva', 'zzzzz', 'x', 'accion_con_guion_bajo', 'informes'] as $desconocida) {
            $this->assertNotContains(
                ColorDeAccion::matiz($desconocida),
                $deConocidas,
                "«{$desconocida}» ha caído en el color de una acción del contrato"
            );
        }
    }

    public function test_ningun_color_cae_en_el_rojo_el_verde_ni_el_naranja(): void
    {
        // **El test que importa.** Rojo, verde y naranja ya tienen significado en el
        // panel: si una acción sale roja, se lee como que ha fallado.
        foreach (['licence', 'sync', 'data', 'setup', 'scss', 'scss-cdn', 'js', 'features',
            'tutorials', 'resources', 'products', 'stats', 'blocks', 'una-accion-nueva',
            'x', 'zzzzz', 'accion_con_guion_bajo'] as $accion) {
            $matiz = ColorDeAccion::matiz($accion);

            $this->assertTrue(
                ($matiz > 45 && $matiz < 95) || $matiz > 155,
                // Con llaves: el lexer de PHP admite bytes altos en los identificadores,
                // asi que "$accion»" se parsea como una variable llamada `accion»`.
                "«{$accion}» cae en un matiz reservado ({$matiz})"
            );
        }
    }

    public function test_sin_accion_no_se_inventa_un_color(): void
    {
        // Una petición sin acción no tiene nada que agrupar: gris del sistema, y además
        // con los tokens del design system, no un hsl a medida.
        foreach ([null, '', '   '] as $vacio) {
            $color = ColorDeAccion::de($vacio);

            $this->assertSame('var(--text-muted)', $color['texto']);
            $this->assertSame('var(--surface-sunken)', $color['fondo']);
        }
    }

    public function test_el_texto_y_el_fondo_comparten_matiz(): void
    {
        // Es lo que hace que la etiqueta se lea como una sola cosa y no como texto de un
        // color encima de un fondo de otro.
        $color = ColorDeAccion::de('features');
        $matiz = ColorDeAccion::matiz('features');

        $this->assertStringStartsWith('hsl(' . $matiz . ',', $color['texto']);
        $this->assertStringStartsWith('hsl(' . $matiz . ',', $color['fondo']);
    }
}
