<?php
namespace EasyChat\View;

final class AccessibleColor {
    public const MODE_AUTO = 'auto';
    public const MODE_LIGHT = 'light';
    public const MODE_DARK = 'dark';

    private const DEFAULT_BACKGROUND = '#6366f1';
    private const LIGHT_FOREGROUND = '#ffffff';
    private const DARK_FOREGROUND = '#111827';
    private const FALLBACK_DARK_FOREGROUND = '#000000';
    private const MIN_TEXT_CONTRAST = 4.5;
     
     
     
    private const AUTO_DARK_LUMINANCE_THRESHOLD = 0.17912878474;

    public static function normalizeHex($value, $fallback = self::DEFAULT_BACKGROUND) {
        $value = strtolower(trim((string)$value));
        if (preg_match('/^#[0-9a-f]{6}$/', $value)) {
            return $value;
        }

        $fallback = strtolower(trim((string)$fallback));
        return preg_match('/^#[0-9a-f]{6}$/', $fallback)
            ? $fallback
            : self::DEFAULT_BACKGROUND;
    }

    public static function normalizeMode($mode) {
        $mode = strtolower(trim((string)$mode));
        return in_array($mode, [self::MODE_AUTO, self::MODE_LIGHT, self::MODE_DARK], true)
            ? $mode
            : self::MODE_AUTO;
    }

    public static function foregroundFor($background, $mode = self::MODE_AUTO) {
        $background = self::normalizeHex($background);
        $mode = self::normalizeMode($mode);
        if ($mode === self::MODE_LIGHT) {
            return self::LIGHT_FOREGROUND;
        }
        if ($mode === self::MODE_DARK) {
            return self::DARK_FOREGROUND;
        }

        $light_contrast = self::contrastRatio($background, self::LIGHT_FOREGROUND);
        $dark_contrast = self::contrastRatio($background, self::DARK_FOREGROUND);
        $background_luminance = self::relativeLuminance($background);
        if ($background_luminance > self::AUTO_DARK_LUMINANCE_THRESHOLD) {
            return $dark_contrast >= self::MIN_TEXT_CONTRAST
                ? self::DARK_FOREGROUND
                : self::FALLBACK_DARK_FOREGROUND;
        }
        if ($light_contrast >= self::MIN_TEXT_CONTRAST) {
            return self::LIGHT_FOREGROUND;
        }

         
         
        return self::contrastRatio($background, self::FALLBACK_DARK_FOREGROUND) >= $light_contrast
            ? self::FALLBACK_DARK_FOREGROUND
            : self::LIGHT_FOREGROUND;
    }

    public static function modeIsAccessible($background, $mode) {
        $background = self::normalizeHex($background);
        $mode = self::normalizeMode($mode);
        if ($mode === self::MODE_AUTO) {
            return true;
        }

        $foreground = $mode === self::MODE_LIGHT
            ? self::LIGHT_FOREGROUND
            : self::DARK_FOREGROUND;

        return self::contrastRatio($background, $foreground) >= self::MIN_TEXT_CONTRAST;
    }

    public static function contrastRatio($first, $second) {
        $first_luminance = self::relativeLuminance(self::normalizeHex($first, '#000000'));
        $second_luminance = self::relativeLuminance(self::normalizeHex($second, '#000000'));
        $lighter = max($first_luminance, $second_luminance);
        $darker = min($first_luminance, $second_luminance);

        return ($lighter + 0.05) / ($darker + 0.05);
    }

    private static function relativeLuminance($hex) {
        $channels = [
            hexdec(substr($hex, 1, 2)) / 255,
            hexdec(substr($hex, 3, 2)) / 255,
            hexdec(substr($hex, 5, 2)) / 255,
        ];

        foreach ($channels as $index => $channel) {
            $channels[$index] = $channel <= 0.04045
                ? $channel / 12.92
                : pow(($channel + 0.055) / 1.055, 2.4);
        }

        return (0.2126 * $channels[0]) + (0.7152 * $channels[1]) + (0.0722 * $channels[2]);
    }
}
