/**
 * Branding utilities for the public SharedReport surface.
 *
 * The design system stores colors as CSS custom properties in the form
 * "H S% L%" (consumed by `hsl(var(--accent))` in app.css). White-labeled
 * reports inject the operator's brand colors into those same variables, so
 * we need a hex → "H S% L%" converter that is defensive against malformed
 * input — the form-request validates strictly on write, but DB rows can be
 * hand-edited or imported, and a malformed `--accent: notacolor;` would
 * silently break paint downstream.
 *
 * All functions return null / a safe fallback for invalid input rather than
 * throwing, so callers can do `style[var] = hsl ?? undefined` and let the
 * default theme bleed through.
 */

const HEX_RE = /^([A-Fa-f0-9]{3}|[A-Fa-f0-9]{6})$/;

/**
 * Convert a #RRGGBB or #RGB hex string to "H S% L%" — the format Tailwind v4
 * uses for hsl()-wrapped CSS custom properties (`hsl(var(--accent))`).
 *
 * Returns null on invalid input so callers can fall back to the default theme
 * rather than emit a broken `--accent: <bad>;` declaration.
 */
export function hexToHslComponents(hex: string | null | undefined): string | null {
  if (typeof hex !== 'string') return null;
  const cleaned = hex.trim().replace(/^#/, '');
  if (!HEX_RE.test(cleaned)) return null;

  const expanded =
    cleaned.length === 3
      ? cleaned
          .split('')
          .map((c) => c + c)
          .join('')
      : cleaned;

  const r = parseInt(expanded.slice(0, 2), 16) / 255;
  const g = parseInt(expanded.slice(2, 4), 16) / 255;
  const b = parseInt(expanded.slice(4, 6), 16) / 255;

  const max = Math.max(r, g, b);
  const min = Math.min(r, g, b);
  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 r:
        h = ((g - b) / d + (g < b ? 6 : 0)) * 60;
        break;
      case g:
        h = ((b - r) / d + 2) * 60;
        break;
      default:
        h = ((r - g) / d + 4) * 60;
    }
  }

  return `${Math.round(h)} ${Math.round(s * 100)}% ${Math.round(l * 100)}%`;
}

/**
 * Pick a readable foreground tuple ("H S% L%") for a given hex.
 *
 * Uses WCAG relative luminance — values brighter than 0.55 get a near-black
 * foreground; everything else gets pure white. Falls back to white for
 * invalid input so a corrupt branding row does not produce illegible text on
 * a default-dark accent. Mirrors the light-mode tokens defined in app.css.
 */
export function readableForegroundHsl(hex: string | null | undefined): string {
  if (typeof hex !== 'string') return '0 0% 100%';
  const cleaned = hex.trim().replace(/^#/, '');
  if (!HEX_RE.test(cleaned)) return '0 0% 100%';

  const expanded =
    cleaned.length === 3
      ? cleaned
          .split('')
          .map((c) => c + c)
          .join('')
      : cleaned;

  const r = parseInt(expanded.slice(0, 2), 16) / 255;
  const g = parseInt(expanded.slice(2, 4), 16) / 255;
  const b = parseInt(expanded.slice(4, 6), 16) / 255;
  const luminance = 0.2126 * r + 0.7152 * g + 0.0722 * b;
  return luminance > 0.55 ? '220 25% 10%' : '0 0% 100%';
}

/**
 * Validate a hex string is safe to inline into a `style` attribute.
 * Used only to gate the leftover `style={{ color: ... }}` paths in
 * ReportPreview that consume the raw hex (not the HSL component form).
 */
export function isSafeHex(hex: string | null | undefined): boolean {
  if (typeof hex !== 'string') return false;
  const cleaned = hex.trim().replace(/^#/, '');
  return HEX_RE.test(cleaned);
}
