/** DOM HUD: status, hotbar, inventory, title + sleep screens, toasts. */
import { CROPS, cropDef, type CropType } from './world.ts';
import { MAX_ENERGY, TOOLS, type GameState, type Tool } from './game.ts';
import { clockString } from './render.ts';
import type { Assets } from './assets.ts';

export interface HudCallbacks {
  onNew: () => void;
  onContinue: () => void;
  onWake: () => void;
  onSleep: () => void;
  onTool: (tool: Tool) => void;
}

const TOOL_LABEL: Record<Tool, string> = { hoe: 'Hoe', can: 'Water', seeds: 'Seeds', scythe: 'Scythe' };

const $ = <T extends HTMLElement = HTMLElement>(id: string): T => document.getElementById(id) as T;

let toolIcons: string[] = [];
let cropIcons: Record<string, string> = {};
let toastTimer = 0;

function iconUrl(canvas: HTMLCanvasElement, size: number): string {
  const c = document.createElement('canvas');
  const ratio = canvas.width / canvas.height;
  c.width = ratio >= 1 ? size : Math.round(size * ratio);
  c.height = ratio >= 1 ? Math.round(size / ratio) : size;
  const cx = c.getContext('2d')!;
  cx.imageSmoothingQuality = 'high';
  cx.drawImage(canvas, 0, 0, c.width, c.height);
  return c.toDataURL();
}

export function initHUD(assets: Assets, cb: HudCallbacks): void {
  toolIcons = assets.tools.map((s) => iconUrl(s.canvas, 56));
  cropIcons = {};
  for (const c of CROPS) cropIcons[c.id] = iconUrl(assets.crops[c.id][2].canvas, 40);

  // hotbar
  const hotbar = $('hotbar');
  hotbar.innerHTML = '';
  TOOLS.forEach((tool, i) => {
    const slot = document.createElement('button');
    slot.className = 'slot';
    slot.id = `slot-${tool}`;
    slot.innerHTML =
      `<span class="key">${i + 1}</span><img alt="${tool}" src="${toolIcons[i]}">` +
      (tool === 'seeds' ? `<img class="seed-badge" id="seed-badge" alt="">` : '') +
      `<span class="slot-label" id="label-${tool}">${TOOL_LABEL[tool]}</span>`;
    slot.addEventListener('pointerdown', (e) => {
      e.preventDefault();
      cb.onTool(tool);
    });
    hotbar.appendChild(slot);
  });

  // title background plate
  ($('title-bg') as HTMLImageElement).src = iconUrl(assets.background.canvas, 1024);

  $('btn-new').addEventListener('click', cb.onNew);
  $('btn-continue').addEventListener('click', cb.onContinue);
  $('btn-wake').addEventListener('click', cb.onWake);
  $('sleep-btn').addEventListener('pointerdown', (e) => {
    e.preventDefault();
    cb.onSleep();
  });

  window.addEventListener('toast', ((e: CustomEvent<string>) => toast(e.detail)) as EventListener);
}

export function toast(msg: string): void {
  const el = $('toast');
  el.textContent = msg;
  el.classList.add('show');
  clearTimeout(toastTimer);
  toastTimer = window.setTimeout(() => el.classList.remove('show'), 1600);
}

/** cheap per-frame bits: clock + energy bar */
export function updateClock(g: GameState): void {
  $('status-day').textContent = `Day ${g.day}`;
  $('status-clock').textContent = clockString(g.time);
  const fill = $('energy-fill');
  const pct = (g.energy / MAX_ENERGY) * 100;
  fill.style.width = `${pct}%`;
  fill.style.background = pct > 40 ? 'linear-gradient(#ffe27a,#f5b942)' : pct > 15 ? 'linear-gradient(#ffc27a,#f58a42)' : 'linear-gradient(#ff8a7a,#e85542)';
  const night = g.time > 0.72;
  $('status-clock').style.color = night ? '#aab4e8' : '#fff6dd';
}

/** heavier bits — call when g.hudDirty */
export function updateHUD(g: GameState): void {
  $('money').textContent = `${g.money}`;

  // inventory chips
  const inv = $('inv');
  inv.innerHTML = '';
  for (const c of CROPS) {
    const n = g.inventory[c.id] ?? 0;
    if (!n) continue;
    const chip = document.createElement('div');
    chip.className = 'chip';
    chip.innerHTML = `<img src="${cropIcons[c.id]}" alt="${c.name}"><b>${n}</b>`;
    inv.appendChild(chip);
  }

  // hotbar selection + seed badge
  for (const tool of TOOLS) {
    $(`slot-${tool}`).classList.toggle('selected', g.tool === tool);
  }
  const seed = CROPS[g.seedIndex];
  ($('seed-badge') as HTMLImageElement).src = cropIcons[seed.id];
  $('label-seeds').textContent = seed.name;

  // overlays follow phase
  $('title-screen').classList.toggle('hidden', g.phase !== 'title');
  $('hud').classList.toggle('hidden', g.phase === 'title');
  const sleepScreen = $('sleep-screen');
  const wasHidden = sleepScreen.classList.contains('hidden');
  sleepScreen.classList.toggle('hidden', g.phase !== 'sleep');
  if (g.phase === 'sleep' && wasHidden) fillSleepScreen(g);
}

function fillSleepScreen(g: GameState): void {
  $('sleep-day').textContent = `Day ${g.day - 1} complete`;
  const list = $('shipped-list');
  list.innerHTML = '';
  if (g.lastShipped.length === 0) {
    list.innerHTML = `<div class="ship-line empty">nothing shipped today — the crops are still dreaming</div>`;
  } else {
    for (const line of g.lastShipped) {
      const el = document.createElement('div');
      el.className = 'ship-line';
      el.innerHTML =
        `<img src="${cropIcons[line.name.toLowerCase() as CropType] ?? ''}" alt="">` +
        `<span>${line.name} × ${line.count}</span><b>${line.gold}g</b>`;
      list.appendChild(el);
    }
  }
  $('sleep-total').innerHTML = g.lastEarned > 0 ? `earned <b>${g.lastEarned}g</b> ✨` : `rest well 🌙`;
}

export function showContinue(hasSave: boolean): void {
  $('btn-continue').classList.toggle('hidden', !hasSave);
}

export function seedName(g: GameState): string {
  return cropDef(CROPS[g.seedIndex].id).name;
}
