<?php

namespace Tests\Unit;

use App\Domain\Shared\Branding\ColorRamp;
use PHPUnit\Framework\TestCase;

/**
 * components/layouts/sidebar.blade.php hardcoded `color: #fff` on the brand
 * accent. This is a tenant-branded product, so a client whose brand is yellow
 * got white text on yellow at about 1.5:1 — unreadable, and unfixable
 * downstream because the value was baked into the markup.
 */
class ColorRampTest extends TestCase
{
    public function test_the_foreground_always_clears_wcag_aa_against_its_own_base(): void
    {
        $brands = [
            '#2563eb', // blue
            '#facc15', // yellow — the case that broke
            '#dc2626', // red
            '#059669', // green
            '#0f172a', // near black
            '#f1f5f9', // near white
            '#7c3aed', // violet
            '#f97316', // orange
            '#06b6d4', // cyan
        ];

        foreach ($brands as $hex) {
            $ramp = ColorRamp::fromHex($hex);
            $ratio = ColorRamp::contrastRatio($ramp->foreground, $hex);

            $this->assertGreaterThanOrEqual(
                4.5,
                $ratio,
                "{$ramp->foreground} on {$hex} is only " . round($ratio, 2) . ':1'
            );
        }
    }

    public function test_the_hardcoded_white_it_replaces_would_have_failed(): void
    {
        // Kept as the regression's own evidence: this is what shipped.
        $this->assertLessThan(2.0, ColorRamp::contrastRatio('#ffffff', '#facc15'));
    }

    public function test_lightness_decreases_monotonically_across_the_ramp(): void
    {
        // Fixed lightness targets break for an inherently light brand: yellow
        // sits at L 0.86, so a table putting 400 at L 0.70 makes 400 darker
        // than 500 and the ramp stops meaning anything.
        foreach (['#2563eb', '#facc15', '#0f172a', '#f1f5f9', '#059669'] as $hex) {
            $previous = 2.0;

            foreach (ColorRamp::fromHex($hex)->shades as $step => $value) {
                preg_match('/oklch\(([\d.]+)/', $value, $m);
                $lightness = (float) $m[1];

                $this->assertLessThanOrEqual(
                    $previous + 0.0001,
                    $lightness,
                    "{$hex} step {$step} is lighter than the step before it"
                );

                $previous = $lightness;
            }
        }
    }

    public function test_the_pale_shades_stay_inside_a_plausible_srgb_chroma(): void
    {
        // At L 0.97 a chroma of 0.10 is outside sRGB and the browser clips it
        // to something muddy.
        foreach (['#2563eb', '#dc2626', '#7c3aed'] as $hex) {
            $shades = ColorRamp::fromHex($hex)->shades;

            preg_match('/oklch\([\d.]+ ([\d.]+)/', $shades[50], $m);

            $this->assertLessThan(0.03, (float) $m[1], "{$hex} step 50 is over-saturated");
        }
    }

    public function test_step_500_is_the_tenant_colour_untouched(): void
    {
        $ramp = ColorRamp::fromHex('#2563eb');

        [$r, $g, $b] = ColorRamp::hexToRgb('#2563eb');
        [$l, $c, $h] = ColorRamp::rgbToOklch($r, $g, $b);

        $this->assertSame(sprintf('oklch(%.4f %.4f %.2f)', $l, $c, $h), $ramp->shades[500]);
    }

    public function test_a_malformed_colour_falls_back_rather_than_throwing(): void
    {
        $this->assertSame('#2563eb', ColorRamp::fromHex('not-a-colour')->base);
        $this->assertSame('#2563eb', ColorRamp::fromHex('')->base);
        $this->assertSame('#aabbcc', ColorRamp::fromHex('abc')->base);
    }
}
