/**
 * DOM HUD: health / shells / keycard readouts plus the obligatory
 * procedural marine face that grimaces as HP drops and glances when you turn.
 */
import type { Game } from './game';

export class Hud {
  private hpEl: HTMLElement;
  private ammoEl: HTMLElement;
  private keyEl: HTMLElement;
  private faceCtx: CanvasRenderingContext2D;
  private look = 0; // -1..1 recent turn direction
  private blinkT = 0;
  private blink = false;
  private lastDraw = -1;

  constructor(root: Document) {
    this.hpEl = root.getElementById('hp-val')!;
    this.ammoEl = root.getElementById('ammo-val')!;
    this.keyEl = root.getElementById('key-icon')!;
    const face = root.getElementById('face') as HTMLCanvasElement;
    this.faceCtx = face.getContext('2d')!;
  }

  notifyTurn(delta: number): void {
    this.look += delta * 2;
    this.look = Math.max(-1, Math.min(1, this.look));
  }

  update(g: Game, dt: number, t: number): void {
    this.hpEl.textContent = String(Math.max(0, Math.ceil(g.hp)));
    this.hpEl.style.color = g.hp > 60 ? '#d8c9a8' : g.hp > 30 ? '#e0a23c' : '#e03c2c';
    this.ammoEl.textContent = String(g.ammo);
    this.ammoEl.style.color = g.ammo > 6 ? '#d8c9a8' : '#e03c2c';
    this.keyEl.classList.toggle('have', g.hasKey);

    this.look *= Math.max(0, 1 - dt * 3);
    this.blinkT -= dt;
    if (this.blinkT <= 0) {
      this.blink = !this.blink;
      this.blinkT = this.blink ? 0.12 : 1.5 + Math.random() * 3;
    }
    // redraw at ~12fps
    const frame = (t * 12) | 0;
    if (frame === this.lastDraw) return;
    this.lastDraw = frame;
    this.drawFace(g, t);
  }

  /** chunky 4px-grid marine face */
  private drawFace(g: Game, t: number): void {
    const c = this.faceCtx;
    const px = (x: number, y: number, w: number, h: number, col: string) => {
      c.fillStyle = col;
      c.fillRect(x * 4, y * 4, w * 4, h * 4);
    };
    const hp = g.hp;
    const dead = g.phase === 'dead' || hp <= 0;
    const tier = dead ? 4 : hp > 70 ? 0 : hp > 45 ? 1 : hp > 20 ? 2 : 3;
    const pain = g.damageFlash > 0.45;

    c.clearRect(0, 0, 48, 48);
    // backplate
    px(0, 0, 12, 12, '#181410');
    // skin tones get bloodier per tier
    const skin = ['#b58a62', '#b08358', '#a87850', '#9c6a46', '#7a5a48'][tier]!;
    const shade = ['#926c4a', '#8d6644', '#855c3e', '#7a5036', '#5f463a'][tier]!;
    // neck + head
    px(4, 10, 4, 2, shade);
    px(2, 2, 8, 8, skin);
    px(2, 8, 8, 2, shade);
    // buzz cut
    px(2, 1, 8, 2, '#4a3526');
    px(2, 3, 1, 2, '#4a3526');
    px(9, 3, 1, 2, '#4a3526');
    // brows: angrier with tier
    const browDrop = tier >= 1 ? 1 : 0;
    px(3, 4, 2, 1, '#3a2a1c');
    px(7, 4, 2, 1, '#3a2a1c');
    if (browDrop) {
      px(4, 4 as number, 1, 1, skin);
      px(7, 4, 1, 1, skin);
      px(4, 5, 1, 1, '#3a2a1c');
      px(7 + 0, 5, 1, 1, '#3a2a1c');
    }
    // eyes (glance with look dir, blink, X when dead)
    if (dead) {
      c.strokeStyle = '#2a1a12';
      c.lineWidth = 2;
      for (const ex of [3.5, 7.5]) {
        c.beginPath();
        c.moveTo(ex * 4 - 3, 5 * 4 - 3); c.lineTo(ex * 4 + 3, 5 * 4 + 3);
        c.moveTo(ex * 4 + 3, 5 * 4 - 3); c.lineTo(ex * 4 - 3, 5 * 4 + 3);
        c.stroke();
      }
    } else if (this.blink && !pain) {
      px(3, 5, 2, 1, shade);
      px(7, 5, 2, 1, shade);
    } else {
      px(3, 5, 2, 1, '#e8e0d0');
      px(7, 5, 2, 1, '#e8e0d0');
      const off = this.look > 0.25 ? 1 : this.look < -0.25 ? 0 : 0.5;
      px(3 + off, 5, 1, 1, '#1a1410');
      px(7 + off, 5, 1, 1, '#1a1410');
    }
    // nose
    px(5, 6, 2, 2, shade);
    // mouth by tier
    if (dead) {
      px(4, 9, 4, 1, '#2a1a12');
    } else if (pain) {
      px(4, 8, 4, 2, '#3a1410');
      px(5, 8, 2, 1, '#e8e0d0');
    } else if (tier === 0) {
      px(4, 9, 4, 1, '#5a3a28');
    } else if (tier === 1) {
      px(4, 9, 4, 1, '#4a2a1c');
      px(3, 8, 1, 1, '#4a2a1c');
    } else if (tier === 2) {
      px(3, 9, 6, 1, '#3a1c12');
      px(4, 8, 1, 1, '#3a1c12');
      px(7, 8, 1, 1, '#3a1c12');
      // blood trickle
      px(8, 6, 1, 3, '#8c1810');
    } else {
      px(3, 8, 6, 2, '#30120c');
      px(4, 8, 4, 1, '#d8d0c0');
      px(2, 5, 1, 4, '#8c1810');
      px(8, 7, 1, 4, '#8c1810');
      px(5, 2, 2, 1, '#8c1810');
    }
    // subtle idle sway
    void t;
  }
}
