export function discoverEffects(records, postFxShaders, luts) {
  const effects = [];
  for (const { track, segment: seg } of records) {
    if (track.type === 'postfx') {
      const shader = postFxShaders[seg.shaderFile];
      if (shader) effects.push({ type: 'postfx', seg, shader, trackId: track.id, order: track.order });
    } else if (track.type === 'lut') {
      const lut = luts[seg.lutFile];
      if (lut) effects.push({ type: 'lut', seg, lut, trackId: track.id, order: track.order });
    }
  }
  return effects;
}

export function configurePostFxMaterial(material, effect, time, width, height) {
  const { seg, shader } = effect;
  const values = seg.uniforms || {};
  material.uniforms.uTexture.value = effect.sourceTexture;
  material.uniforms.uTime.value = time;
  material.uniforms.uResolution.value.set(width, height);
  material.uniforms.uIntensity.value = Math.max(0, Math.min(1, values.intensity ?? 1.0));
  if (material.uniforms.uOpacity) material.uniforms.uOpacity.value = values.opacity ?? 1.0;
  const defaults = {
    uBloomStrength: 0.6,
    uBloomThreshold: 0.3,
    uVignetteStrength: 0.5,
    uChromaticAberration: 0.003,
    uSaturation: 1.0,
    uContrast: 1.0,
    uBrightness: 1.0,
  };
  for (const [uniform, fallback] of Object.entries(defaults)) {
    if (material.uniforms[uniform]) material.uniforms[uniform].value = values[uniform] ?? fallback;
  }
  if (material.uniforms.uColorTint) {
    material.uniforms.uColorTint.value.set(
      values.uColorTintR ?? 1.0,
      values.uColorTintG ?? 1.0,
      values.uColorTintB ?? 1.0
    );
  }
  for (const param of shader.params || []) {
    if (material.uniforms[param.uniform]) {
      material.uniforms[param.uniform].value = values[param.uniform] ?? param.default;
    }
  }
  return material;
}

export function configureLutMaterial(material, effect) {
  const { seg, lut } = effect;
  material.uniforms.uTexture.value = effect.sourceTexture;
  material.uniforms.uLUT.value = lut.texture3D;
  material.uniforms.uLUTSize.value = lut.size;
  material.uniforms.uIntensity.value = seg.intensity ?? 1.0;
  material.uniforms.uLiftR.value = (seg.liftR ?? 0.0) + (seg.liftMaster ?? 0.0);
  material.uniforms.uLiftG.value = (seg.liftG ?? 0.0) + (seg.liftMaster ?? 0.0);
  material.uniforms.uLiftB.value = (seg.liftB ?? 0.0) + (seg.liftMaster ?? 0.0);
  material.uniforms.uGammaR.value = (seg.gammaR ?? 1.0) * (seg.gammaMaster ?? 1.0);
  material.uniforms.uGammaG.value = (seg.gammaG ?? 1.0) * (seg.gammaMaster ?? 1.0);
  material.uniforms.uGammaB.value = (seg.gammaB ?? 1.0) * (seg.gammaMaster ?? 1.0);
  material.uniforms.uGainR.value = (seg.gainR ?? 1.0) * (seg.gainMaster ?? 1.0);
  material.uniforms.uGainG.value = (seg.gainG ?? 1.0) * (seg.gainMaster ?? 1.0);
  material.uniforms.uGainB.value = (seg.gainB ?? 1.0) * (seg.gainMaster ?? 1.0);
  return material;
}

export function runEffectChain(effects, sourceTarget, destTarget, applyEffect) {
  for (let index = 0; index < effects.length; index++) {
    const result = applyEffect(
      effects[index],
      sourceTarget,
      destTarget,
      index === effects.length - 1
    );
    [sourceTarget, destTarget] = result;
  }
  return [sourceTarget, destTarget];
}
