/**
 * sfxFactories — процедурная генерация звуковых эффектов для GD-игры.
 *
 * Каждый SFX = функция playXxx(ctx, masterGain) которая ставит осцилляторы/шум
 * и сразу проигрывает звук. Без файлов.
 *
 * Все 9 эффектов согласно RUBLOX_GD_GDD.md §8:
 *   jump, death, orb_tap, bounce, whoosh, flip, coin, level_complete, new_record
 */

// ============================================================
// УТИЛИТЫ
// ============================================================

/**
 * Создать один тон-осциллятор с ADSR-огибающей.
 */
function tone(ctx, dest, opts) {
  const {
    freq, freqEnd = freq, wave = 'sine',
    attack = 0.005, decay = 0.0, sustain = 1.0, release = 0.1,
    duration = 0.15, gain = 0.3,
    filter = null,   // { type, freq, q }
  } = opts;
  const t0 = ctx.currentTime;

  const osc = ctx.createOscillator();
  osc.type = wave;
  osc.frequency.setValueAtTime(freq, t0);
  if (freqEnd !== freq) {
    osc.frequency.exponentialRampToValueAtTime(Math.max(freqEnd, 1), t0 + duration);
  }

  const g = ctx.createGain();
  g.gain.setValueAtTime(0, t0);
  g.gain.linearRampToValueAtTime(gain, t0 + attack);
  if (decay > 0) {
    g.gain.linearRampToValueAtTime(gain * sustain, t0 + attack + decay);
  }
  g.gain.linearRampToValueAtTime(0, t0 + duration);

  let lastNode = osc;
  if (filter) {
    const f = ctx.createBiquadFilter();
    f.type = filter.type || 'lowpass';
    f.frequency.value = filter.freq || 1000;
    f.Q.value = filter.q || 1;
    osc.connect(f);
    lastNode = f;
  }
  lastNode.connect(g);
  g.connect(dest);

  osc.start(t0);
  osc.stop(t0 + duration + 0.05);
}

/**
 * Короткий "взрыв" шума с фильтром (для удара / снэра).
 */
function noiseBurst(ctx, dest, opts) {
  const {
    duration = 0.15, gain = 0.3,
    filterType = 'highpass', filterFreq = 1000, filterQ = 1,
  } = opts;
  const t0 = ctx.currentTime;
  const len = Math.max(1, Math.floor(ctx.sampleRate * duration));
  const buf = ctx.createBuffer(1, len, ctx.sampleRate);
  const d = buf.getChannelData(0);
  for (let i = 0; i < len; i++) {
    d[i] = (Math.random() * 2 - 1) * (1 - i / len);
  }
  const src = ctx.createBufferSource();
  src.buffer = buf;

  const f = ctx.createBiquadFilter();
  f.type = filterType;
  f.frequency.value = filterFreq;
  f.Q.value = filterQ;

  const g = ctx.createGain();
  g.gain.setValueAtTime(gain, t0);
  g.gain.exponentialRampToValueAtTime(0.001, t0 + duration);

  src.connect(f);
  f.connect(g);
  g.connect(dest);
  src.start(t0);
  src.stop(t0 + duration + 0.05);
}


// ============================================================
// 9 ЭФФЕКТОВ
// ============================================================

/** Прыжок — короткий восходящий "whoop". */
export function playJump(ctx, master) {
  tone(ctx, master, {
    freq: 280, freqEnd: 520, wave: 'triangle',
    duration: 0.13, gain: 0.25, attack: 0.005, release: 0.1,
  });
}

/** Смерть — низкий "smash" с шумом. */
export function playDeath(ctx, master) {
  // Низкочастотный осциллятор который падает
  tone(ctx, master, {
    freq: 200, freqEnd: 60, wave: 'sawtooth',
    duration: 0.4, gain: 0.28,
  });
  // Шумовой взрыв сверху
  noiseBurst(ctx, master, {
    duration: 0.25, gain: 0.22,
    filterType: 'bandpass', filterFreq: 400, filterQ: 1,
  });
}

/** Тап по orb — звон. */
export function playOrbTap(ctx, master) {
  tone(ctx, master, {
    freq: 880, freqEnd: 1760, wave: 'sine',
    duration: 0.18, gain: 0.22,
  });
  // обертон
  tone(ctx, master, {
    freq: 1320, wave: 'triangle',
    duration: 0.12, gain: 0.12,
  });
}

/** Трамплин — пружина "boing". */
export function playBounce(ctx, master) {
  tone(ctx, master, {
    freq: 200, freqEnd: 600, wave: 'square',
    duration: 0.2, gain: 0.22,
    filter: { type: 'lowpass', freq: 1500, q: 4 },
  });
  // лёгкий шум для "wobble"
  noiseBurst(ctx, master, {
    duration: 0.08, gain: 0.06,
    filterType: 'bandpass', filterFreq: 800, filterQ: 2,
  });
}

/** Speed pad — шипящий swoosh. */
export function playWhoosh(ctx, master) {
  noiseBurst(ctx, master, {
    duration: 0.35, gain: 0.28,
    filterType: 'bandpass', filterFreq: 2500, filterQ: 3,
  });
  // тональная подложка
  tone(ctx, master, {
    freq: 400, freqEnd: 1200, wave: 'sawtooth',
    duration: 0.3, gain: 0.1,
    filter: { type: 'lowpass', freq: 3000, q: 1 },
  });
}

/** Gravity flip — короткое "wo-op" + glitch. */
export function playFlip(ctx, master) {
  tone(ctx, master, {
    freq: 800, freqEnd: 200, wave: 'square',
    duration: 0.15, gain: 0.2,
  });
  // обратный slide через 80мс
  setTimeout(() => {
    tone(ctx, master, {
      freq: 200, freqEnd: 600, wave: 'triangle',
      duration: 0.15, gain: 0.18,
    });
  }, 80);
}

/** Монета — двойной звон вверх. */
export function playCoin(ctx, master) {
  tone(ctx, master, {
    freq: 988, wave: 'square',
    duration: 0.08, gain: 0.18,
  });
  setTimeout(() => {
    tone(ctx, master, {
      freq: 1318, wave: 'square',
      duration: 0.15, gain: 0.2,
    });
  }, 70);
}

/** Уровень пройден — короткие фанфары: тоника-квинта-октава. */
export function playLevelComplete(ctx, master) {
  const root = 523.25;  // C5
  const notes = [
    { f: root,        delay: 0,    dur: 0.18 },     // C
    { f: root * 1.5,  delay: 150,  dur: 0.18 },     // G
    { f: root * 2,    delay: 300,  dur: 0.45 },     // C октава
  ];
  for (const n of notes) {
    setTimeout(() => {
      tone(ctx, master, {
        freq: n.f, wave: 'square',
        duration: n.dur, gain: 0.22,
        attack: 0.01, release: 0.1,
      });
      tone(ctx, master, {
        freq: n.f * 2, wave: 'triangle',
        duration: n.dur * 0.6, gain: 0.1,
      });
    }, n.delay);
  }
}

/** Новый рекорд — восходящая короткая мелодия 5 нот. */
export function playNewRecord(ctx, master) {
  const root = 523.25;
  // C - E - G - C - E (мажорное трезвучие + октава)
  const ratios = [1, 1.26, 1.5, 2, 2.52];
  ratios.forEach((r, i) => {
    setTimeout(() => {
      tone(ctx, master, {
        freq: root * r, wave: 'square',
        duration: 0.14, gain: 0.22,
      });
      tone(ctx, master, {
        freq: root * r * 2, wave: 'triangle',
        duration: 0.1, gain: 0.1,
      });
    }, i * 80);
  });
  // Финальная высокая нота
  setTimeout(() => {
    tone(ctx, master, {
      freq: root * 4, wave: 'sine',
      duration: 0.4, gain: 0.18,
    });
  }, ratios.length * 80);
}


// ============================================================
// РЕЕСТР
// ============================================================

export const SFX_CATALOG = [
  {
    id: 'jump', title: 'Прыжок', emoji: '⬆',
    description: 'Короткий восходящий «whoop» при тапе чтобы прыгнуть',
    play: playJump, durationMs: 130,
  },
  {
    id: 'death', title: 'Смерть', emoji: '💥',
    description: 'Низкий «smash» с шумом при касании шипа или падении в холу',
    play: playDeath, durationMs: 400,
  },
  {
    id: 'orb_tap', title: 'Jump Orb', emoji: '🟡',
    description: 'Звон при активации жёлтого orba в воздухе',
    play: playOrbTap, durationMs: 180,
  },
  {
    id: 'bounce', title: 'Трамплин', emoji: '🟠',
    description: 'Пружина «boing» при отскоке от оранжевого трамплина',
    play: playBounce, durationMs: 200,
  },
  {
    id: 'whoosh', title: 'Speed pad', emoji: '🔵',
    description: 'Шипящий swoosh при ускорении от голубого пада',
    play: playWhoosh, durationMs: 350,
  },
  {
    id: 'flip', title: 'Gravity Flip', emoji: '🟣',
    description: 'Wo-op + обратный slide при перевороте гравитации',
    play: playFlip, durationMs: 250,
  },
  {
    id: 'coin', title: 'Монета', emoji: '🪙',
    description: 'Двойной звон вверх при сборе монеты',
    play: playCoin, durationMs: 230,
  },
  {
    id: 'level_complete', title: 'Уровень пройден', emoji: '🏁',
    description: 'Короткие фанфары: тоника-квинта-октава при достижении финиша',
    play: playLevelComplete, durationMs: 750,
  },
  {
    id: 'new_record', title: 'Новый рекорд', emoji: '⭐',
    description: 'Восходящая мелодия 5 нот + высокая финальная нота',
    play: playNewRecord, durationMs: 800,
  },
];
