import { loadAssets } from './assets';
import { Sfx } from './audio';
import { Game, type Phase } from './game';
import { Hud } from './hud';
import { Input } from './input';
import { Renderer } from './render';

declare global {
  interface Window {
    __game: {
      phase: Phase;
      hp: number;
      ammo: number;
      enemies: number;
      hasKey: boolean;
      x: number;
      y: number;
      angle: number;
      teleport: (x: number, y: number, angle?: number) => void;
      fire: () => void;
    };
  }
}

async function boot(): Promise<void> {
  const out = document.getElementById('view') as HTMLCanvasElement;
  const overlay = document.getElementById('overlay')!;
  const ovTitle = document.getElementById('ov-title')!;
  const ovSub = document.getElementById('ov-sub')!;
  const ovBtn = document.getElementById('ov-btn')!;
  const ovBackdrop = document.getElementById('ov-backdrop')!;

  ovSub.textContent = 'LOADING HULL…';
  ovBtn.style.display = 'none';

  const assets = await loadAssets();
  if (assets.backdropUrl) {
    ovBackdrop.style.backgroundImage = `url(${assets.backdropUrl})`;
  }

  const sfx = new Sfx();
  const game = new Game(sfx);
  const renderer = new Renderer(out, assets, game);
  const input = new Input(
    document.getElementById('view')!,
    document.getElementById('stick')!,
    document.getElementById('nub')!,
    document.getElementById('firebtn')!,
  );
  const hud = new Hud(document);
  input.onFirstInteract = () => sfx.unlock();
  input.onTapFire = () => game.fire();

  // crisp output canvas sized to its CSS box
  const fit = (): void => {
    const r = out.getBoundingClientRect();
    const dpr = Math.min(2, window.devicePixelRatio || 1);
    out.width = Math.max(2, Math.round(r.width * dpr));
    out.height = Math.max(2, Math.round(r.height * dpr));
  };
  fit();
  window.addEventListener('resize', fit);

  window.__game = {
    get phase() { return game.phase; },
    get hp() { return game.hp; },
    get ammo() { return game.ammo; },
    get enemies() { return game.aliveEnemies(); },
    get hasKey() { return game.hasKey; },
    get x() { return game.px; },
    get y() { return game.py; },
    get angle() { return game.angle; },
    teleport: (x, y, angle) => game.teleport(x, y, angle),
    fire: () => game.fire(),
  };

  let shownPhase: Phase | '' = '';
  const syncOverlay = (): void => {
    if (game.phase === shownPhase) return;
    shownPhase = game.phase;
    if (game.phase === 'playing') {
      overlay.classList.add('hidden');
      return;
    }
    overlay.classList.remove('hidden');
    ovBtn.style.display = '';
    if (game.phase === 'title') {
      ovTitle.textContent = 'HULLROT';
      ovSub.innerHTML =
        'freighter <b>KOVCHEG-9</b> went dark in the belt.<br>' +
        'salvage crew found the hold… occupied.<br><br>' +
        'left stick — move · drag view — turn · tap — fire';
      ovBtn.textContent = 'BOARD THE WRECK';
    } else if (game.phase === 'dead') {
      ovTitle.textContent = 'YOU ARE CARGO NOW';
      ovSub.textContent = `the rot takes another. kills: ${game.kills}`;
      ovBtn.textContent = 'TRY AGAIN';
    } else {
      ovTitle.textContent = 'EXTRACTION COMPLETE';
      ovSub.textContent =
        `you made it off the wreck — ${game.kills} hostiles down, ` +
        `${Math.round(game.time)}s on the clock.`;
      ovBtn.textContent = 'DIVE AGAIN';
    }
  };
  syncOverlay();

  ovBtn.addEventListener('click', () => {
    sfx.unlock();
    game.reset();
    game.phase = 'playing';
    syncOverlay();
    (ovBtn as HTMLButtonElement).blur(); // or Space-to-fire would re-click it
  });

  let last = performance.now();
  let time = 0;
  const loop = (now: number): void => {
    const dt = Math.min(0.05, (now - last) / 1000);
    last = now;
    time += dt;
    const turnBefore = input.state.turnDelta;
    game.update(dt, input);
    hud.notifyTurn(turnBefore);
    renderer.render(time);
    hud.update(game, dt, time);
    if (game.phase === 'playing') sfx.update(dt);
    syncOverlay();
    requestAnimationFrame(loop);
  };
  requestAnimationFrame(loop);
}

void boot();
