/**
 * PaintHUD — a tiny DOM overlay: per-colour coverage bars + the active buff kit.
 * No framework, no per-frame layout thrash (throttled to ~10Hz and only rewrites
 * text/width, never rebuilds nodes).
 */
import type { BlobModifiers, CoverageReport, PaintColor } from '../contracts'
import { PALETTE } from '../contracts'
import { COLOR_ORDER, ACTIVATE, SUPER } from './coverage-math'

export class PaintHUD {
  readonly root: HTMLDivElement
  private readonly bars = new Map<PaintColor, { fill: HTMLDivElement; pct: HTMLSpanElement }>()
  private readonly totalPct: HTMLSpanElement
  private readonly buffLine: HTMLDivElement
  private lastUpdate = -1e9

  constructor(container: HTMLElement = document.body) {
    const root = document.createElement('div')
    root.style.cssText = [
      'position:fixed', 'top:12px', 'left:12px', 'z-index:10',
      'font:12px/1.4 ui-monospace,SFMono-Regular,Menlo,monospace',
      'color:#fff', 'background:rgba(18,18,24,0.72)', 'padding:10px 12px',
      'border-radius:10px', 'min-width:210px', 'user-select:none',
      'box-shadow:0 4px 18px rgba(0,0,0,0.35)', 'backdrop-filter:blur(4px)',
    ].join(';')

    const title = document.createElement('div')
    title.textContent = 'PAINT COVERAGE'
    title.style.cssText = 'font-weight:700;letter-spacing:0.08em;opacity:0.85;margin-bottom:8px'
    root.appendChild(title)

    for (const color of COLOR_ORDER) {
      const row = document.createElement('div')
      row.style.cssText = 'display:flex;align-items:center;gap:6px;margin:3px 0'

      const swatch = document.createElement('div')
      swatch.style.cssText = `width:10px;height:10px;border-radius:3px;background:${PALETTE[color]};flex:0 0 auto`
      row.appendChild(swatch)

      const track = document.createElement('div')
      track.style.cssText = 'flex:1;height:8px;background:rgba(255,255,255,0.12);border-radius:4px;overflow:hidden'
      const fill = document.createElement('div')
      fill.style.cssText = `height:100%;width:0%;background:${PALETTE[color]};transition:width 0.12s linear`
      track.appendChild(fill)
      row.appendChild(track)

      const pct = document.createElement('span')
      pct.textContent = '0%'
      pct.style.cssText = 'width:34px;text-align:right;opacity:0.9'
      row.appendChild(pct)

      root.appendChild(row)
      this.bars.set(color, { fill, pct })
    }

    const totalRow = document.createElement('div')
    totalRow.style.cssText = 'margin-top:8px;border-top:1px solid rgba(255,255,255,0.15);padding-top:6px'
    totalRow.innerHTML = 'total painted: '
    this.totalPct = document.createElement('span')
    this.totalPct.textContent = '0%'
    this.totalPct.style.fontWeight = '700'
    totalRow.appendChild(this.totalPct)
    root.appendChild(totalRow)

    this.buffLine = document.createElement('div')
    this.buffLine.style.cssText = 'margin-top:6px;opacity:0.95;min-height:16px'
    root.appendChild(this.buffLine)

    container.appendChild(root)
    this.root = root
  }

  /** Call each frame; internally throttled to ~10Hz. */
  update(cov: CoverageReport, mods: BlobModifiers): void {
    const now = performance.now()
    if (now - this.lastUpdate < 100) return
    this.lastUpdate = now

    for (const color of COLOR_ORDER) {
      const b = this.bars.get(color)!
      const v = cov.byColor[color]
      b.fill.style.width = `${Math.min(100, v * 100).toFixed(0)}%`
      b.pct.textContent = `${(v * 100).toFixed(0)}%`
      const active = v >= ACTIVATE
      b.pct.style.opacity = active ? '1' : '0.5'
      b.fill.style.boxShadow = v >= SUPER ? `0 0 8px ${PALETTE[color]}` : 'none'
    }
    this.totalPct.textContent = `${(cov.total * 100).toFixed(0)}%`

    this.buffLine.innerHTML = this.buffText(cov, mods)
  }

  private buffText(cov: CoverageReport, mods: BlobModifiers): string {
    const parts: string[] = []
    if (cov.byColor.red >= ACTIVATE) parts.push(`<b style="color:${PALETTE.red}">BURN</b> ×${mods.speedMul.toFixed(2)}`)
    if (cov.byColor.green >= ACTIVATE) parts.push(`<b style="color:${PALETTE.green}">GRIP</b> ${mods.grip.toFixed(2)}`)
    if (cov.byColor.blue >= ACTIVATE) parts.push(`<b style="color:${PALETTE.blue}">SLICK</b> waterproof`)
    parts.push(`mass ×${mods.massMul.toFixed(2)}`)
    if (mods.glow > 0) parts.push('<b style="color:#fff;text-shadow:0 0 6px #fff">★ SUPER</b>')
    return parts.length ? parts.join(' &nbsp;·&nbsp; ') : '<span style="opacity:0.5">no buffs</span>'
  }

  dispose(): void {
    this.root.remove()
  }
}
