/**
 * LANE-UI — the commission fax. The fax machine is sacred, do not ask why it works
 * (lore §6). Sits under THE SCREEN, top right.
 *
 * Progress comes from `snap.commissionProgress` (itemId -> count delivered), measured
 * against the active CommissionDef's `wants`.
 */
import type { CommissionDef, GameData, ItemDef, SimSnapshot } from '../contracts';
import { createChipRow, type ChipRow } from './chips';
import { commissionChips } from './chipspec';
import { cls, el, panel, text } from './dom';
import { COPY } from './voice';

export interface Fax {
  el: HTMLElement;
  update(snap: SimSnapshot): void;
  /** Play the stamp. Driven by the `commissionDone` event, not by progress math. */
  stamp(): void;
}

const STAMP_MS = 1800; // must match the fk-stamp keyframes in style.ts

/**
 * The Correction quietly buys these back (lore §5; the fiction lands properly in M3).
 * Hardcoded id sanctioned by round-2 orders.
 */
const SANITISED_ITEM = 'anchor-slab';

export function createFax(data: GameData): Fax {
  const commissions = new Map<string, CommissionDef>(data.commissions.map((c) => [c.id, c]));
  const items = new Map<string, ItemDef>(data.items.map((i) => [i.id, i]));

  const root = panel();
  root.id = 'fk-fax';

  const head = el('div', 'fk-h fk-fax-h', [COPY.faxHeader]);
  const sub = el('div', 'fk-fax-sub', [COPY.faxSubheader]);
  const flavor = el('div', 'fk-fax-flavor');
  const chips: ChipRow = createChipRow(items);
  const reward = el('div', 'fk-fax-sub');

  // SANITISING: shown once The Correction has something to buy back.
  const sanHead = el('div', 'fk-h fk-san-h', [COPY.sanitising]);
  const sanChips: ChipRow = createChipRow(items);
  const sanWrap = el('div', 'fk-san', [sanHead, sanChips.el]);

  // NEXT IN TRAY: the peek at what the tray is holding.
  const nextHead = el('div', 'fk-h', [COPY.faxNext]);
  const nextName = el('div', 'fk-fax-next-name');
  const nextChips: ChipRow = createChipRow(items);
  const nextWrap = el('div', 'fk-fax-next', [
    el('div', 'fk-rule'), nextHead, nextName, nextChips.el,
  ]);

  const standing = el('div', 'fk-fax-standing', [el('span', undefined, [COPY.faxStanding])]);
  const stampEl = el('div', 'fk-fax-stamp', [el('span', undefined, [COPY.faxStamp])]);

  root.append(head, sub, flavor, el('div', 'fk-rule'), chips.el, reward,
    sanWrap, nextWrap, standing, stampEl);

  let stampTimer: number | undefined;

  /**
   * What the tray is actually holding.
   *
   * `snap.commissionQueue` (contracts v3) is the truth: active first, then upcoming in
   * activation order — so the peek is `queue[1]`. The round-2 data-order inference is
   * gone; it was a guess that went wrong the moment a completed standing order was
   * re-queued to the back, and a fax that lies quietly is worse than a fax that says
   * nothing. If the field is absent, we show no peek.
   */
  function peekNext(snap: SimSnapshot, activeId: string): CommissionDef | null {
    const queue = snap.commissionQueue;
    if (!queue) return null;
    const nextId = queue[0] === activeId ? queue[1] : queue[0];
    return (nextId && commissions.get(nextId)) || null;
  }

  return {
    el: root,
    update(snap) {
      const c = snap.activeCommission ? commissions.get(snap.activeCommission) : null;
      cls(root, 'is-open', !!c);
      if (!c) return;

      text(flavor, c.flavor);
      chips.update(commissionChips(c, snap.commissionProgress));
      text(reward, `ON RECEIPT: +${c.rewardBandwidth} BANDWIDTH`);

      cls(standing, 'is-on', c.repeat === true);

      const sanitised = snap.shippedTotal[SANITISED_ITEM] ?? 0;
      cls(sanWrap, 'is-on', sanitised > 0);
      if (sanitised > 0) {
        sanChips.update([{ item: SANITISED_ITEM, count: String(sanitised), state: 'plain' }]);
      }

      const next = peekNext(snap, c.id);
      cls(nextWrap, 'is-on', !!next);
      if (next) {
        text(nextName, next.id.replace(/-/g, ' ').toUpperCase());
        nextChips.update(
          Object.entries(next.wants).map(([item, need]) => ({ item, count: String(need) })),
        );
      }
    },
    stamp() {
      // Restart cleanly if two commissions complete back to back.
      cls(stampEl, 'is-on', false);
      void stampEl.offsetWidth; // force reflow so the animation re-runs
      cls(stampEl, 'is-on', true);
      clearTimeout(stampTimer);
      stampTimer = window.setTimeout(() => cls(stampEl, 'is-on', false), STAMP_MS);
    },
  };
}
