import type { BasicFilters, CurvesState } from "./types";
import { interpolateSpline, isIdentityCurve } from "./curves";

export function buildCSSFilter(basic: BasicFilters): string {
  const parts: string[] = [];

  // Brightness: slider 0-200, CSS brightness(0-2)
  parts.push(`brightness(${basic.brightness / 100})`);

  // Contrast: slider 0-200, CSS contrast(0-2)
  parts.push(`contrast(${basic.contrast / 100})`);

  // Saturation: slider 0-200, CSS saturate(0-2)
  parts.push(`saturate(${basic.saturation / 100})`);

  // Exposure: -100 to 100, maps to exponential brightness multiplier
  if (basic.exposure !== 0) {
    const exposureMult = Math.pow(2, basic.exposure / 100);
    parts.push(`brightness(${exposureMult})`);
  }

  // Temperature: -100 (cool) to 100 (warm)
  if (basic.temperature !== 0) {
    const absTemp = Math.abs(basic.temperature) / 100;
    const sepia = absTemp * 0.3;
    parts.push(`sepia(${sepia})`);
    if (basic.temperature < 0) {
      parts.push(`hue-rotate(180deg)`);
    }
    parts.push(`saturate(${1 + absTemp * 0.2})`);
  }

  // Tint: -100 to 100, maps to hue-rotate -30 to 30 degrees
  if (basic.tint !== 0) {
    const deg = (basic.tint / 100) * 30;
    parts.push(`hue-rotate(${deg}deg)`);
  }

  return parts.join(" ");
}

export interface LUTResult {
  r: Uint8Array;
  g: Uint8Array;
  b: Uint8Array;
  isIdentity: boolean;
}

export function buildLUT(basic: BasicFilters, curves: CurvesState): LUTResult {
  const curvesIdentity =
    isIdentityCurve(curves.rgb) &&
    isIdentityCurve(curves.r) &&
    isIdentityCurve(curves.g) &&
    isIdentityCurve(curves.b);

  const noHighlightsShadows = basic.highlights === 0 && basic.shadows === 0;

  if (curvesIdentity && noHighlightsShadows) {
    const identity = new Uint8Array(256);
    for (let i = 0; i < 256; i++) identity[i] = i;
    return { r: identity, g: identity, b: identity, isIdentity: true };
  }

  // Start with highlight/shadow adjustments
  const baseLut = new Uint8Array(256);
  for (let i = 0; i < 256; i++) {
    let val = i;

    // Shadows: gamma on lower half (values < 128)
    if (basic.shadows !== 0) {
      const shadowGamma = 1 - basic.shadows / 200;
      if (i < 128) {
        const t = i / 128;
        const adjusted = Math.pow(t, shadowGamma) * 128;
        val = adjusted + (val - i);
      }
    }

    // Highlights: gamma on upper half (values > 128)
    if (basic.highlights !== 0) {
      const highlightGamma = 1 - basic.highlights / 200;
      if (val > 128) {
        const t = (val - 128) / 127;
        val = 128 + Math.pow(t, highlightGamma) * 127;
      }
    }

    baseLut[i] = Math.max(0, Math.min(255, Math.round(val)));
  }

  // Apply curves on top
  const rgbLut = interpolateSpline(curves.rgb);
  const rCurve = interpolateSpline(curves.r);
  const gCurve = interpolateSpline(curves.g);
  const bCurve = interpolateSpline(curves.b);

  const r = new Uint8Array(256);
  const g = new Uint8Array(256);
  const b = new Uint8Array(256);

  for (let i = 0; i < 256; i++) {
    const base = baseLut[i];
    const afterRgb = rgbLut[base];
    r[i] = rCurve[afterRgb];
    g[i] = gCurve[afterRgb];
    b[i] = bCurve[afterRgb];
  }

  return { r, g, b, isIdentity: false };
}
