import { Game, LEVELS } from './game.js';
import { View } from './renderer.js';
import { AudioEngine } from './audio.js';
import { Storage } from './storage.js';
import { startBackground } from './fxbg.js';
import { LEVEL1_WIN } from './demo.js';
import {
  $,
  applyTheme,
  showScreen,
  bindSettingsForm,
  readSettingsForm,
  renderScores,
  showLevelIntro,
  updateHud,
  showResult,
  hideResult,
  showPause,
} from './ui.js';

const audio = new AudioEngine();
const view = new View($('board-canvas'), $('queue-canvas'));
let game = null;
let raf = 0;
let last = 0;
let playing = false;
let pendingMode = null;
let pendingLevel = 0;

function settings() {
  return Storage.settings();
}

function bootGame(seed) {
  game = new Game({ ...settings() }, seed || Date.now());
  view.setPalette(settings().palette);
  view.particles.clear();
  game.on(onEvent);
  expose();
  return game;
}

function onEvent(type, data) {
  if (type === 'place') {
    audio.place();
    view.burstPlace(data.x, data.y, false);
  }
  if (type === 'replace') {
    audio.replace();
    view.burstPlace(data.x, data.y, true);
  }
  if (type === 'rotate') audio.rotate();
  if (type === 'undo') audio.undo();
  if (type === 'warn') audio.warn();
  if (type === 'valve') audio.valve();
  if (type === 'cell') audio.cell();
  if (type === 'combo') audio.combo(data.n);
  if (type === 'leak-fail') audio.leakFail();
  if (type === 'leak-win') audio.leakWin();
  if (type === 'win') {
    view.burstWin(game);
    finishRun(true);
  }
  if (type === 'lose') finishRun(false);
}

function finishRun(ok) {
  if (ok && game.mode === 'campaign') Storage.unlock(game.levelIndex + 2);
  const campaignOver = game.mode === 'campaign' && (game.result?.last || !ok);
  const endlessOver = game.mode === 'endless' && !ok;
  if (campaignOver || endlessOver) {
    Storage.recordScore({
      name: Storage.player(),
      score: game.mode === 'campaign' ? game.campaignScore : game.levelScore,
      mode: game.mode,
      level: game.mode === 'campaign' ? game.level.id : game.distance,
      difficulty: settings().difficulty,
    });
  }
  showResult(game);
}

function layout() {
  const wrap = document.querySelector('.board-wrap');
  if (!wrap) return;
  const r = wrap.getBoundingClientRect();
  view.resize(r.width, r.height);
}

function loop(ts) {
  raf = requestAnimationFrame(loop);
  if (!last) last = ts;
  let dt = (ts - last) / 1000;
  last = ts;
  if (dt > 0.05) dt = 0.05;
  if (!playing || !game) return;
  game.settings = { ...game.settings, ...settings() };
  view.particles.enabled = settings().particles;
  game.update(dt);
  view.update(dt, game);
  view.draw(game);
  view.drawQueue(game);
  updateHud(game);
}

function enterGame() {
  hideResult();
  showPause(false);
  showScreen('game');
  playing = true;
  layout();
  requestAnimationFrame(layout);
  last = 0;
}

function startCampaignFrom(levelIndex) {
  audio.unlock();
  audio.startMusic();
  pendingMode = 'campaign';
  pendingLevel = levelIndex;
  bootGame();
  game.startCampaign(levelIndex);
  showLevelIntro(game);
}

function startEndless() {
  audio.unlock();
  audio.startMusic();
  pendingMode = 'endless';
  bootGame();
  game.startEndless();
  showLevelIntro(game);
}

function confirmLevel() {
  enterGame();
}

function toTitle() {
  playing = false;
  showPause(false);
  hideResult();
  showScreen('title');
  const u = Storage.unlocked();
  $('btn-continue').hidden = u <= 1;
  $('btn-continue').textContent = `Continue S${String(Math.min(LEVELS.length, u)).padStart(2, '0')}`;
}

function bindBoard() {
  const c = $('board-canvas');
  c.addEventListener('pointermove', (e) => {
    if (!game || !playing) return;
    const r = c.getBoundingClientRect();
    view.hover = view.gridAt(e.clientX - r.left, e.clientY - r.top, game);
  });
  c.addEventListener('pointerleave', () => {
    view.hover = null;
  });
  c.addEventListener('pointerdown', (e) => {
    if (!game || !playing) return;
    audio.unlock();
    if (e.button === 2) {
      game.rotateHeld(1);
      e.preventDefault();
      return;
    }
    const r = c.getBoundingClientRect();
    const g = view.gridAt(e.clientX - r.left, e.clientY - r.top, game);
    if (g) game.placeAt(g.x, g.y);
  });
  c.addEventListener('contextmenu', (e) => e.preventDefault());
}

function bindKeys() {
  addEventListener('keydown', (e) => {
    const tag = (e.target && e.target.tagName) || '';
    if (tag === 'INPUT' || tag === 'SELECT' || tag === 'TEXTAREA') return;
    if (!game) {
      if (e.key === 'Enter' && !document.getElementById('screen-title').hidden) {
        startCampaignFrom(0);
      }
      return;
    }
    if (e.key === 'Escape') {
      if (game.phase === 'paused') {
        game.resume();
        showPause(false);
      } else if (playing) {
        game.pause();
        showPause(true);
      }
    }
    if (!playing) return;
    if (e.key === 'r' || e.key === 'R') game.rotateHeld(1);
    if (e.key === 'z' || e.key === 'Z') game.undo();
    if (e.key === ' ') {
      e.preventDefault();
      if (game.phase === 'countdown') game.beginFlow();
      else if (game.phase === 'flowing') game.toggleFast();
    }
    if (e.key === 'f' || e.key === 'F') game.toggleFast();
  });
}

function applyAudioFromSettings() {
  const s = settings();
  audio.setVolumes({ master: s.master, music: s.music, sfx: s.sfx });
}

function bindUi() {
  $('btn-play').onclick = () => startCampaignFrom(0);
  $('btn-continue').onclick = () =>
    startCampaignFrom(Math.min(LEVELS.length - 1, Math.max(0, Storage.unlocked() - 1)));
  function refreshContinue() {
    const u = Storage.unlocked();
    $('btn-continue').hidden = u <= 1;
    $('btn-continue').textContent = `Continue S${String(Math.min(LEVELS.length, u)).padStart(2, '0')}`;
  }
  refreshContinue();
  $('btn-endless').onclick = () => startEndless();
  $('btn-howto').onclick = () => showScreen('howto');
  $('btn-scores').onclick = () => {
    renderScores();
    showScreen('scores');
  };
  $('btn-settings').onclick = () => {
    bindSettingsForm();
    showScreen('settings');
  };
  document.querySelectorAll('[data-back]').forEach((b) => {
    b.onclick = () => {
      if (b.closest('#screen-settings')) readSettingsForm();
      applyAudioFromSettings();
      toTitle();
    };
  });
  ['set-master', 'set-music', 'set-sfx', 'set-palette', 'set-diff'].forEach((id) => {
    $(id).addEventListener('input', () => {
      readSettingsForm();
      applyAudioFromSettings();
      if (game) {
        game.settings = { ...game.settings, ...settings() };
        view.setPalette(settings().palette);
      }
    });
  });
  ['set-rotate', 'set-ghost', 'set-undo', 'set-shake', 'set-particles', 'set-motion'].forEach(
    (id) => {
      $(id).addEventListener('change', () => {
        readSettingsForm();
        if (game) game.settings = { ...game.settings, ...settings() };
      });
    }
  );
  $('set-name').addEventListener('change', () => Storage.setPlayer($('set-name').value));
  $('btn-clear-scores').onclick = () => {
    Storage.resetScores();
    renderScores();
  };
  $('btn-level-go').onclick = () => confirmLevel();
  $('btn-pause').onclick = () => {
    if (!game) return;
    game.pause();
    showPause(true);
  };
  $('btn-resume').onclick = () => {
    game.resume();
    showPause(false);
  };
  $('btn-retry').onclick = () => {
    showPause(false);
    hideResult();
    game.retryLevel();
    enterGame();
  };
  $('btn-quit').onclick = () => toTitle();
  $('btn-rotate').onclick = () => game && game.rotateHeld(1);
  $('btn-undo').onclick = () => game && game.undo();
  $('btn-valve').onclick = () => game && game.beginFlow();
  $('btn-fast').onclick = () => game && game.toggleFast();
  $('btn-next').onclick = () => {
    hideResult();
    if (game.result?.last) {
      toTitle();
      return;
    }
    game.nextLevel();
    showLevelIntro(game);
    playing = false;
  };
  $('btn-again').onclick = () => {
    hideResult();
    game.retryLevel();
    enterGame();
  };
  $('btn-home').onclick = () => toTitle();
  $('res-name').addEventListener('change', () => Storage.setPlayer($('res-name').value));
}

function applyShot(params) {
  const screen = params.get('screen') || params.get('shot');
  if (!screen) return false;
  if (screen === 'howto') {
    showScreen('howto');
    return true;
  }
  if (screen === 'scores') {
    if (!Storage.top(1).length) {
      ['ACE', 'VALVE', 'FLOOZ', 'PIPE'].forEach((n, i) => {
        Storage.recordScore({
          name: n,
          score: 18000 - i * 2100,
          mode: 'campaign',
          level: 8 - i,
          difficulty: 'normal',
        });
      });
    }
    renderScores();
    showScreen('scores');
    return true;
  }
  if (screen === 'settings') {
    bindSettingsForm();
    showScreen('settings');
    return true;
  }
  if (screen === 'play' || screen === 'mid' || screen === 'win') {
    startCampaignFrom(Number(params.get('level') || 2));
    confirmLevel();
    if (screen === 'mid' || screen === 'win') seedDemo(screen === 'win');
    return true;
  }
  return false;
}

function seedDemo(win) {
  const g = game;
  for (const [x, y, id] of LEVEL1_WIN) {
    g.queue[0] = id;
    g.placeAt(x, y);
  }
  g.beginFlow();
  const steps = win ? 50 : 10;
  for (let t = 0; t < steps; t++) g.update(0.2);
}

function expose() {
  window.__conduit = { game, view, audio, Storage, startCampaignFrom, enterGame };
}

function main() {
  applyTheme(settings().palette);
  view.setPalette(settings().palette);
  bindSettingsForm();
  applyAudioFromSettings();
  startBackground($('fx-bg'), () => settings().palette);
  bindUi();
  bindBoard();
  bindKeys();
  addEventListener('resize', layout);
  addEventListener('pointerdown', () => audio.unlock(), { once: true });
  showScreen('title');
  requestAnimationFrame(loop);

  const params = new URLSearchParams(location.search);
  applyShot(params);
  expose();
}

main();

void LEVELS;
