/**
 * LANE-UI — top strip: bandwidth meter, shipped ticker, run state.
 *
 * The brownout has to be legible from this panel alone — it is the one failure the
 * player must read across the room, so it gets the border, the color, and the flash.
 */
import type { GameData, ItemDef, SimSnapshot } from '../contracts';
import { createChipRow, type ChipRow } from './chips';
import type { Corrections } from './corrections';
import { cls, el, panel, style, text } from './dom';
import { formatReserve, powerState } from './power';
import { COPY } from './voice';

export interface TopStrip {
  el: HTMLElement;
  /** `corrections` is the session tally of The Correction's edits — surfaced only once
   *  the first mite has struck, so it never signposts an enemy that hasn't arrived. */
  update(snap: SimSnapshot, corrections?: Corrections): void;
}

function stat(label: string, valueCls?: string): { row: HTMLElement; v: HTMLElement } {
  const v = el('span', valueCls ? `fk-stat-v ${valueCls}` : 'fk-stat-v');
  const row = el('div', 'fk-stat', [el('span', undefined, [label]), v]);
  return { row, v };
}

export function createTopStrip(data: GameData): TopStrip {
  const root = panel();
  root.id = 'fk-top';

  const head = el('div', 'fk-h', [COPY.bandwidth]);

  const drawEl = el('span', 'fk-bw-draw');
  const genEl = el('span');
  const nums = el('div', 'fk-bw-nums', [drawEl, genEl]);

  const fill = el('div', 'fk-bar-f');
  const bar = el('div', 'fk-bar', [fill]);

  const brownout = el('div');
  brownout.id = 'fk-brownout';
  brownout.textContent = COPY.brownout;

  // Amber, not red: the factory is surviving on stored charge, not failing.
  const reserve = el('div');
  reserve.id = 'fk-reserve';

  const buffer = stat('BUFFER', 'fk-buf');
  const shipped = stat(COPY.shipped);
  const run = stat(COPY.tick);
  run.v.id = 'fk-run';

  const items = new Map<string, ItemDef>(data.items.map((i) => [i.id, i]));
  const chips: ChipRow = createChipRow(items);

  // CORRECTED ticker (round 6): a count + per-item chips of what the mites have "fixed".
  // Hidden until the first edit, so pre-Correction play never sees the enemy named.
  const corrected = stat(COPY.correctedLabel, 'fk-corrected-v');
  cls(corrected.row, 'fk-corrected', true);
  const correctedChips: ChipRow = createChipRow(items);
  const correctedWrap = el('div', 'fk-corrected-wrap', [corrected.row, correctedChips.el]);
  style(correctedWrap, 'display', 'none');

  root.append(head, nums, bar, brownout, reserve, el('div', 'fk-rule'),
    buffer.row, shipped.row, run.row, chips.el, correctedWrap);

  return {
    el: root,
    update(snap, corrections) {
      const { gen, draw, stored, capacity } = snap.bandwidth;

      text(drawEl, `${draw.toFixed(0)} DRAW`);
      text(genEl, `${gen.toFixed(0)} GEN`);

      // BROWNOUT is the sim's flag and nothing else. A covered deficit is the tanks
      // doing their job, and it gets its own amber word — see power.ts.
      const p = powerState(snap.bandwidth);
      style(fill, 'width', `${Math.min(1, p.ratio) * 100}%`);
      cls(root, 'is-tight', p.state === 'tight');
      cls(root, 'is-reserve', p.state === 'reserve');
      cls(root, 'is-brownout', p.state === 'brownout');

      if (p.state === 'reserve') {
        text(reserve, `${COPY.onReserve} · ${formatReserve(p.reserveSeconds!)}`);
      }

      // Capacity (v4) turns the buffer readout into a fuel gauge rather than a number.
      text(buffer.v, capacity ? `${stored.toFixed(0)}/${capacity.toFixed(0)}` : stored.toFixed(0));

      let total = 0;
      for (const n of Object.values(snap.shippedTotal)) total += n;
      text(shipped.v, String(total));

      text(run.v, snap.paused ? COPY.paused : `${snap.tick}`);
      cls(run.v, 'is-paused', snap.paused);

      chips.update(
        Object.entries(snap.shippedTotal)
          .filter(([, n]) => n > 0)
          .map(([item, n]) => ({ item, count: String(n), state: 'met' as const })),
      );

      const edits = corrections?.total() ?? 0;
      style(correctedWrap, 'display', edits > 0 ? '' : 'none');
      if (edits > 0) {
        text(corrected.v, String(edits));
        correctedChips.update(
          corrections!.byItem().map(({ item, count }) => ({
            item, count: String(count), state: 'short' as const,
          })),
        );
      }
    },
  };
}
