/** 工場の環境音。稼働中の機械の数に応じてハム音とコンベアの唸りが濃くなる。 */
import { ensureAudio, getBuses } from './engine';

interface Layer {
  hum: OscillatorNode;
  hum2: OscillatorNode;
  rumble: AudioBufferSourceNode;
  gain: GainNode;
  wobble: OscillatorNode;
}

let layer: Layer | null = null;
let target = 0;

/** 環境音のループを立ち上げる (初回のみ)。 */
function ensureLayer(): Layer | null {
  if (layer) return layer;
  const b = ensureAudio();
  if (!b) return null;

  const gain = b.ctx.createGain();
  gain.gain.value = 0;
  gain.connect(b.ambience);

  // 電源トランスのハム (50Hz とその上の倍音)
  const humGain = b.ctx.createGain();
  humGain.gain.value = 0.35;
  humGain.connect(gain);

  const hum = b.ctx.createOscillator();
  hum.type = 'sawtooth';
  hum.frequency.value = 50;
  const hum2 = b.ctx.createOscillator();
  hum2.type = 'sine';
  hum2.frequency.value = 100.7;

  const humLp = b.ctx.createBiquadFilter();
  humLp.type = 'lowpass';
  humLp.frequency.value = 220;
  hum.connect(humLp);
  hum2.connect(humLp);
  humLp.connect(humGain);

  // コンベアの唸り (低域ノイズ)
  const rumble = b.ctx.createBufferSource();
  rumble.buffer = b.noise;
  rumble.loop = true;
  const rumbleLp = b.ctx.createBiquadFilter();
  rumbleLp.type = 'lowpass';
  rumbleLp.frequency.value = 420;
  const rumbleGain = b.ctx.createGain();
  rumbleGain.gain.value = 0.5;
  rumble.connect(rumbleLp);
  rumbleLp.connect(rumbleGain);
  rumbleGain.connect(gain);

  // ゆっくりした揺らぎで「機械が回っている」感じを出す
  const wobble = b.ctx.createOscillator();
  wobble.type = 'sine';
  wobble.frequency.value = 0.23;
  const wobbleDepth = b.ctx.createGain();
  wobbleDepth.gain.value = 0.18;
  wobble.connect(wobbleDepth);
  wobbleDepth.connect(rumbleGain.gain);

  hum.start();
  hum2.start();
  rumble.start();
  wobble.start();

  layer = { hum, hum2, rumble, gain, wobble };
  return layer;
}

/**
 * 環境音の濃さを設定する。
 * @param intensity 0..1 (0で無音)
 */
export function setAmbience(intensity: number): void {
  const l = ensureLayer();
  const b = getBuses();
  if (!l || !b) return;
  const next = Math.max(0, Math.min(1, intensity));
  if (Math.abs(next - target) < 0.01) return;
  target = next;
  l.gain.gain.setTargetAtTime(next, b.ctx.currentTime, 0.4);
}

export function stopAmbience(): void {
  setAmbience(0);
}
