/**
 * @adia-ai/web-components/color — typed surface for OKLCH color math + APCA contrast
 * computation. §301 (v0.5.12, FEEDBACK-29 re-bucket).
 *
 * Pure functions; no DOM/runtime side-effects. Math sources documented in
 * the corresponding `.js` file.
 */

/** Cartesian-OKLab triple. L ∈ [0, 1]; a, b roughly ∈ [-0.4, 0.4]. */
export interface OKLab {
  L: number;
  a: number;
  b: number;
}

/** Cylindrical-OKLCH triple. L ∈ [0, 1]; C ≥ 0; H ∈ [0, 360) degrees. */
export interface OKLCH {
  L: number;
  C: number;
  H: number;
}

/** Maximum chroma supported by the gamut-mapping helpers (`0.4`). */
export const MAX_CHROMA: number;

/** Tolerance for in-gamut checks (`0.001`). */
export const GAMUT_EPSILON: number;

// ── OKLCH ↔ OKLab ─────────────────────────────────────────────────────────

/** Convert OKLCH (cylindrical) to OKLab (Cartesian). H is in degrees. */
export function oklchToOklab(L: number, C: number, H: number): OKLab;

/** Convert OKLab (Cartesian) to OKLCH (cylindrical). H returned in degrees [0, 360). */
export function oklabToOklch(L: number, a: number, b: number): OKLCH;

// ── OKLab ↔ sRGB (via linear sRGB) ────────────────────────────────────────

/**
 * OKLab → linear sRGB. Returns `[r, g, b]` in `[0, 1]` (unclamped — channels
 * may exceed range when the OKLab point is outside sRGB gamut).
 */
export function oklabToLinearSrgb(L: number, a: number, b: number): [number, number, number];

/** sRGB transfer function: linear → gamma-encoded sRGB. */
export function linearToSrgb(c: number): number;

/** Inverse sRGB transfer function: gamma-encoded sRGB → linear. */
export function srgbToLinear(c: number): number;

/**
 * OKLCH → sRGB clamped to `[0, 1]`. Returns `[r, g, b]`. Out-of-gamut
 * colors are channel-clamped; use `gamutMapChroma()` first for the closest
 * in-gamut color via chroma reduction.
 */
export function oklchToRgb(L: number, C: number, H: number): [number, number, number];

// ── Hex ↔ OKLCH ───────────────────────────────────────────────────────────

/**
 * Convert sRGB `[r, g, b]` (each in `[0, 1]`) to hex string `#rrggbb`.
 * Channel values are rounded to the nearest byte; out-of-range clamped.
 */
export function rgbToHex(r: number, g: number, b: number): string;

/** OKLCH → hex string `#rrggbb`. Channel-clamped to sRGB gamut. */
export function oklchToHex(L: number, C: number, H: number): string;

/**
 * Hex string `#rgb` or `#rrggbb` → OKLCH. H in degrees [0, 360).
 * Accepts both 3- and 6-digit shorthand; tolerant of leading `#`.
 */
export function hexToOklch(hex: string): OKLCH;

// ── Gamut checking + mapping ──────────────────────────────────────────────

/** Returns true if all 3 sRGB channels lie in `[0, 1]` (tolerance `0.001`). */
export function isInGamut(r: number, g: number, b: number): boolean;

/** Returns true if the OKLCH triple is inside sRGB gamut. */
export function isOklchInGamut(L: number, C: number, H: number): boolean;

/**
 * Bisect chroma to find the largest value that keeps `(L, _, H)` in sRGB
 * gamut. Used when the consumer requests a chroma outside the displayable
 * range. 8 bisection iterations — completes in <1ms.
 */
export function gamutMapChroma(L: number, C: number, H: number): number;

// ── Display-P3 gamut (v0.5.13 §-TBD, FB-31) ──────────────────────────────

/**
 * Returns true if the OKLCH triple is inside Display-P3 gamut (tolerance
 * `0.001`). sRGB-linear → P3-linear conversion uses the CSS Color 4 § 12.3
 * matrix (D65 → D65; no Bradford adaptation needed).
 */
export function inP3Gamut(L: number, C: number, H: number): boolean;

/**
 * Bisect chroma to find the largest value that keeps `(L, _, H)` in
 * Display-P3 gamut. 8 bisection iterations — same shape as the sRGB
 * `gamutMapChroma`. Used by P3-aware design tooling.
 */
export function gamutMapChromaP3(L: number, C: number, H: number): number;

// ── APCA (advanced perceptual contrast algorithm) ─────────────────────────

/**
 * Compute APCA contrast (Lc) between a foreground hex color and a
 * background hex color. Returns the signed Lc value:
 *   - Positive = dark text on light bg ("normal polarity")
 *   - Negative = light text on dark bg ("reverse polarity")
 *
 * Typical thresholds (from APCA's "Bronze Simple Mode"):
 *   - Body text:        |Lc| ≥ 75 (4.5:1 WCAG analog)
 *   - Large/bold text:  |Lc| ≥ 60 (3:1 WCAG analog)
 *   - Incidental:       |Lc| ≥ 45 (chrome, decorative)
 *
 * @see https://www.myndex.com/APCA/
 */
export function apcaContrast(fgHex: string, bgHex: string): number;

/**
 * Convenience: choose a foreground (light or dark) that maximizes APCA
 * contrast against the given background hex. Returns either '#000000' or
 * '#ffffff'. Used by `<swatch-ui auto-contrast>`'s OKLab-L probe.
 */
export function pickContrastingFg(bgHex: string): '#000000' | '#ffffff';

// ── LCH-space distance (perceptual distance) ──────────────────────────────

/**
 * Compute perceptual distance between two OKLCH triples.
 * Returns Euclidean distance in OKLab space — perceptually uniform.
 * Useful for "closest swatch in a palette" lookups.
 */
export function oklchDistance(a: OKLCH, b: OKLCH): number;
