"use client";

import type { MediaType } from "./types";

let sharedCtx: AudioContext | null = null;

function getCtx(): AudioContext | null {
  if (typeof window === "undefined") return null;
  const AC =
    window.AudioContext ||
    (window as unknown as { webkitAudioContext: typeof AudioContext })
      .webkitAudioContext;
  if (!AC) return null;
  if (!sharedCtx) sharedCtx = new AC();
  if (sharedCtx.state === "suspended") void sharedCtx.resume();
  return sharedCtx;
}

function tone(
  ctx: AudioContext,
  {
    freq,
    type = "square",
    start = 0,
    duration = 0.08,
    gain = 0.08,
    slideTo,
  }: {
    freq: number;
    type?: OscillatorType;
    start?: number;
    duration?: number;
    gain?: number;
    slideTo?: number;
  },
) {
  const now = ctx.currentTime + start;
  const osc = ctx.createOscillator();
  const g = ctx.createGain();
  osc.type = type;
  osc.frequency.setValueAtTime(freq, now);
  if (slideTo != null) {
    osc.frequency.exponentialRampToValueAtTime(
      Math.max(20, slideTo),
      now + duration,
    );
  }
  g.gain.setValueAtTime(0.0001, now);
  g.gain.exponentialRampToValueAtTime(gain, now + 0.01);
  g.gain.exponentialRampToValueAtTime(0.0001, now + duration);
  osc.connect(g);
  g.connect(ctx.destination);
  osc.start(now);
  osc.stop(now + duration + 0.02);
}

function noiseBurst(
  ctx: AudioContext,
  start: number,
  duration: number,
  gain = 0.05,
) {
  const sampleRate = ctx.sampleRate;
  const length = Math.floor(sampleRate * duration);
  const buffer = ctx.createBuffer(1, length, sampleRate);
  const data = buffer.getChannelData(0);
  for (let i = 0; i < length; i++) {
    data[i] = (Math.random() * 2 - 1) * (1 - i / length);
  }
  const src = ctx.createBufferSource();
  const g = ctx.createGain();
  const filter = ctx.createBiquadFilter();
  filter.type = "bandpass";
  filter.frequency.value = 1800;
  src.buffer = buffer;
  g.gain.value = gain;
  src.connect(filter);
  filter.connect(g);
  g.connect(ctx.destination);
  src.start(ctx.currentTime + start);
}

/** Play a short boot bed for the given media type. */
export function playBootSequence(media: MediaType) {
  const ctx = getCtx();
  if (!ctx) return () => undefined;

  const stoppers: Array<() => void> = [];

  if (media === "cartridge") {
    noiseBurst(ctx, 0.05, 0.12, 0.04);
    tone(ctx, { freq: 220, start: 0.35, duration: 0.06, gain: 0.07 });
    tone(ctx, {
      freq: 140,
      type: "triangle",
      start: 0.55,
      duration: 0.18,
      gain: 0.09,
      slideTo: 90,
    });
    tone(ctx, {
      freq: 880,
      type: "sine",
      start: 0.85,
      duration: 0.35,
      gain: 0.05,
      slideTo: 440,
    });
  } else if (media === "disc") {
    tone(ctx, {
      freq: 90,
      type: "sawtooth",
      start: 0.1,
      duration: 0.35,
      gain: 0.03,
      slideTo: 60,
    });
    noiseBurst(ctx, 0.45, 0.15, 0.035);
    // Spin-up whine
    tone(ctx, {
      freq: 200,
      type: "sawtooth",
      start: 0.7,
      duration: 1.1,
      gain: 0.04,
      slideTo: 920,
    });
    tone(ctx, {
      freq: 2400,
      type: "sine",
      start: 1.4,
      duration: 0.2,
      gain: 0.03,
    });
  } else if (media === "handheld") {
    tone(ctx, { freq: 320, start: 0.15, duration: 0.05, gain: 0.06 });
    tone(ctx, {
      freq: 180,
      type: "triangle",
      start: 0.45,
      duration: 0.25,
      gain: 0.07,
      slideTo: 120,
    });
    // Soft boot chime
    tone(ctx, {
      freq: 523,
      type: "sine",
      start: 0.85,
      duration: 0.2,
      gain: 0.05,
    });
    tone(ctx, {
      freq: 659,
      type: "sine",
      start: 1.0,
      duration: 0.25,
      gain: 0.045,
    });
    tone(ctx, {
      freq: 784,
      type: "sine",
      start: 1.15,
      duration: 0.35,
      gain: 0.04,
    });
  } else {
    // Arcade: coin + start
    tone(ctx, {
      freq: 1400,
      type: "square",
      start: 0.1,
      duration: 0.07,
      gain: 0.06,
      slideTo: 900,
    });
    tone(ctx, {
      freq: 1800,
      type: "square",
      start: 0.18,
      duration: 0.08,
      gain: 0.05,
      slideTo: 1100,
    });
    noiseBurst(ctx, 0.35, 0.08, 0.03);
    tone(ctx, {
      freq: 440,
      type: "square",
      start: 0.7,
      duration: 0.12,
      gain: 0.08,
    });
    tone(ctx, {
      freq: 660,
      type: "square",
      start: 0.85,
      duration: 0.18,
      gain: 0.07,
    });
  }

  // Also try layered WAV samples if present
  const sampleMap: Record<MediaType, string[]> = {
    cartridge: ["/sfx/cart-insert.wav", "/sfx/power-on.wav"],
    disc: ["/sfx/disc-spin.wav", "/sfx/laser.wav"],
    handheld: ["/sfx/click.wav", "/sfx/chime.wav"],
    arcade: ["/sfx/coin.wav", "/sfx/start.wav"],
  };

  for (const src of sampleMap[media]) {
    const audio = new Audio(src);
    audio.volume = 0.55;
    void audio.play().catch(() => undefined);
    stoppers.push(() => {
      audio.pause();
      audio.currentTime = 0;
    });
  }

  return () => {
    for (const stop of stoppers) stop();
  };
}
