/** Parse the data-oriented subset of the Adobe/DaVinci .cube format. */
export function parseCubeLUT(cubeText, warn = console.warn) {
  let title = 'Untitled LUT';
  let size = 0;
  const data = [];

  for (const line of cubeText.split('\n')) {
    const trimmed = line.trim();
    if (!trimmed || trimmed.startsWith('#')) continue;

    const titleMatch = trimmed.match(/^TITLE\s+"([^"]+)"/i);
    if (titleMatch) {
      title = titleMatch[1];
      continue;
    }

    const sizeMatch = trimmed.match(/^LUT_3D_SIZE\s+(\d+)/i);
    if (sizeMatch) {
      size = Number.parseInt(sizeMatch[1], 10);
      continue;
    }

    if (/^(DOMAIN_|LUT_1D)/i.test(trimmed)) continue;

    const values = trimmed.split(/\s+/).map(Number.parseFloat);
    if (values.length >= 3 && !Number.isNaN(values[0])) {
      data.push(values[0], values[1], values[2]);
    }
  }

  if (size === 0 || data.length === 0) {
    throw new Error('Invalid .cube file format');
  }

  const expectedCount = size * size * size * 3;
  if (data.length !== expectedCount) {
    warn(`[LUT] Data mismatch: got ${data.length}, expected ${expectedCount}`);
  }

  return { title, size, data: new Float32Array(data) };
}

/** Convert normalized LUT RGB floats into RGBA bytes for a 3D texture. */
export function lutToRgba8({ size, data }) {
  const textureData = new Uint8Array(size * size * size * 4);
  for (let index = 0; index < size * size * size; index += 1) {
    for (let channel = 0; channel < 3; channel += 1) {
      const value = Math.min(1, Math.max(0, data[index * 3 + channel]));
      textureData[index * 4 + channel] = Math.round(value * 255);
    }
    textureData[index * 4 + 3] = 255;
  }
  return textureData;
}

const LUT_CLIP_PARAMETER_FIELDS = Object.freeze({
  lut_intensity: 'intensity',
  lut_lift_master: 'liftMaster',
  lut_lift_r: 'liftR',
  lut_lift_g: 'liftG',
  lut_lift_b: 'liftB',
  lut_gamma_master: 'gammaMaster',
  lut_gamma_r: 'gammaR',
  lut_gamma_g: 'gammaG',
  lut_gamma_b: 'gammaB',
  lut_gain_master: 'gainMaster',
  lut_gain_r: 'gainR',
  lut_gain_g: 'gainG',
  lut_gain_b: 'gainB',
});

/** Apply a keyframed/LFO LUT control to the segment data consumed by rendering. */
export function applyLutClipParameter(segment, paramId, value) {
  if (!segment) return false;
  const field = LUT_CLIP_PARAMETER_FIELDS[paramId];
  const numericValue = Number(value);
  if (!field || !Number.isFinite(numericValue)) return false;
  segment[field] = numericValue;
  return true;
}
