<?php

namespace App\Support;

/**
 * Deriva a escala completa de uma cor a partir de um único hex.
 *
 * A interface usa onze tons (50 a 950) — pedir todos ao usuário seria
 * inviável. A cor escolhida vira o tom 600; os claros saem misturando branco
 * e os escuros, preto, nas mesmas proporções do Tailwind.
 */
class Paleta
{
    /** Proporção de mistura por tom: positivo clareia, negativo escurece. */
    private const ESCALA = [
        50 => 0.95,
        100 => 0.90,
        200 => 0.75,
        300 => 0.55,
        400 => 0.30,
        500 => 0.12,
        600 => 0.0,
        700 => -0.14,
        800 => -0.28,
        900 => -0.44,
        950 => -0.62,
    ];

    /**
     * @return array<int, string> tom => hex
     */
    public static function gerar(string $hex): array
    {
        [$r, $g, $b] = self::paraRgb($hex);

        $paleta = [];

        foreach (self::ESCALA as $tom => $fator) {
            $paleta[$tom] = $fator >= 0
                ? self::paraHex(
                    self::misturar($r, 255, $fator),
                    self::misturar($g, 255, $fator),
                    self::misturar($b, 255, $fator),
                )
                : self::paraHex(
                    self::misturar($r, 0, -$fator),
                    self::misturar($g, 0, -$fator),
                    self::misturar($b, 0, -$fator),
                );
        }

        return $paleta;
    }

    public static function hexValido(?string $hex): bool
    {
        return (bool) preg_match('/^#[0-9a-fA-F]{6}$/', (string) $hex);
    }

    /**
     * Luminância relativa (WCAG), para decidir entre texto claro e escuro
     * sobre a cor escolhida.
     */
    public static function claro(string $hex): bool
    {
        [$r, $g, $b] = self::paraRgb($hex);

        $canal = fn (int $c) => ($v = $c / 255) <= 0.03928 ? $v / 12.92 : (($v + 0.055) / 1.055) ** 2.4;

        return (0.2126 * $canal($r) + 0.7152 * $canal($g) + 0.0722 * $canal($b)) > 0.45;
    }

    /** @return array{0: int, 1: int, 2: int} */
    private static function paraRgb(string $hex): array
    {
        $hex = ltrim($hex, '#');

        if (strlen($hex) === 3) {
            $hex = $hex[0].$hex[0].$hex[1].$hex[1].$hex[2].$hex[2];
        }

        return [
            (int) hexdec(substr($hex, 0, 2)),
            (int) hexdec(substr($hex, 2, 2)),
            (int) hexdec(substr($hex, 4, 2)),
        ];
    }

    private static function misturar(int $origem, int $alvo, float $peso): int
    {
        return (int) round($origem + ($alvo - $origem) * $peso);
    }

    private static function paraHex(int $r, int $g, int $b): string
    {
        return sprintf('#%02x%02x%02x', max(0, min(255, $r)), max(0, min(255, $g)), max(0, min(255, $b)));
    }
}
