// Adapted from jalcoui (MIT) — github.com/jal-co/ui

import type { ColorFormat } from './types';

/**
 * Parse a `#rrggbb` / `#rgb` hex string into `{ r, g, b }` (0–255).
 * Returns `null` for malformed input.
 */
function parseHex(hex: string): { r: number; g: number; b: number } | null {
  const cleaned = hex.trim().replace(/^#/, '');
  if (cleaned.length === 3) {
    const r = parseInt(cleaned[0] + cleaned[0], 16);
    const g = parseInt(cleaned[1] + cleaned[1], 16);
    const b = parseInt(cleaned[2] + cleaned[2], 16);
    if ([r, g, b].some(Number.isNaN)) return null;
    return { r, g, b };
  }
  if (cleaned.length === 6) {
    const r = parseInt(cleaned.slice(0, 2), 16);
    const g = parseInt(cleaned.slice(2, 4), 16);
    const b = parseInt(cleaned.slice(4, 6), 16);
    if ([r, g, b].some(Number.isNaN)) return null;
    return { r, g, b };
  }
  return null;
}

function rgbToHsl(
  r: number,
  g: number,
  b: number,
): { h: number; s: number; l: number } {
  const rn = r / 255;
  const gn = g / 255;
  const bn = b / 255;
  const max = Math.max(rn, gn, bn);
  const min = Math.min(rn, gn, bn);
  const l = (max + min) / 2;
  let h = 0;
  let s = 0;
  if (max !== min) {
    const d = max - min;
    s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
    switch (max) {
      case rn:
        h = (gn - bn) / d + (gn < bn ? 6 : 0);
        break;
      case gn:
        h = (bn - rn) / d + 2;
        break;
      case bn:
        h = (rn - gn) / d + 4;
        break;
    }
    h /= 6;
  }
  return { h: Math.round(h * 360), s: Math.round(s * 100), l: Math.round(l * 100) };
}

/**
 * Format a hex color into the requested {@link ColorFormat}. Falls
 * back to the original string when the hex is unparseable.
 */
export function formatColor(hex: string, format: ColorFormat): string {
  if (format === 'hex') return hex.toLowerCase();
  const rgb = parseHex(hex);
  if (!rgb) return hex;
  if (format === 'rgb') return `rgb(${rgb.r}, ${rgb.g}, ${rgb.b})`;
  const { h, s, l } = rgbToHsl(rgb.r, rgb.g, rgb.b);
  return `hsl(${h}, ${s}%, ${l}%)`;
}

/**
 * Return `'light'` when the hex color is bright enough that black
 * text reads better against it, otherwise `'dark'`. Uses standard
 * Rec. 601 luminance (`0.299·R + 0.587·G + 0.114·B`).
 */
export function getReadableContrast(hex: string): 'light' | 'dark' {
  const rgb = parseHex(hex);
  if (!rgb) return 'dark';
  const luminance = (0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b) / 255;
  return luminance > 0.6 ? 'light' : 'dark';
}
