// engine.jsx — pure logic for the arc. No rendering.
// Exposes helpers on window for the phase components.

const clamp = (v, lo = 0, hi = 100) => Math.max(lo, Math.min(hi, v));

// Accumulate a profile delta object into a running tally.
function applyProfile(tally, delta) {
  const out = { ...tally };
  for (const k in (delta || {})) out[k] = (out[k] || 0) + delta[k];
  return out;
}

// Normalize the raw escape profile into -1..1 per dimension + derived seeds + read.
function normalizeProfile(raw, flags) {
  const DIMS = ["nerve", "mercy", "guile", "resolve", "defiance"];
  const n = {};
  // empirical cap — total possible swing per dim across the prologue is ~±12
  for (const d of DIMS) n[d] = Math.max(-1, Math.min(1, (raw[d] || 0) / 12));

  // Seed the four pillars (start 50, nudged by who you were).
  const seeds = {
    military: clamp(50 - 14 * n.mercy - 10 * n.defiance + 6 * n.nerve, 30, 72),
    people:   clamp(50 + 16 * n.mercy + 8 * n.defiance - 4 * n.guile, 30, 72),
    economy:  clamp(50 + 12 * n.guile + (flags.took_money ? 7 : 0) - 5 * n.resolve, 30, 72),
    foreign:  clamp(50 + 10 * n.mercy + 8 * n.resolve - 6 * n.nerve, 30, 72),
  };
  for (const k in seeds) seeds[k] = Math.round(seeds[k]);

  // Dominant dimension → archetype label + Algorithm "read".
  const sorted = [...DIMS].sort((a, b) => Math.abs(n[b]) - Math.abs(n[a]));
  const top = sorted[0];
  const sign = n[top] >= 0 ? "+" : "-";
  const ARCH = {
    "mercy+":    { tag: "THE SOFT HAND", read: "You spent risk to spare strangers. The system reads this as instability — or as the only thing it cannot manufacture." },
    "mercy-":    { tag: "THE CLEAN RECORD", read: "When the cost was someone else's, you paid it without flinching. You will find the chair comfortable." },
    "nerve+":    { tag: "THE GAMBLER", read: "You moved toward danger, repeatedly, on purpose. Useful in a fugitive. Catastrophic in a head of state." },
    "nerve-":    { tag: "THE SURVIVOR", read: "You took the safe path each time it was offered. Survival is a strategy. It is rarely a legacy." },
    "guile+":    { tag: "THE FORGER", read: "You worked the seams of the system instead of breaking it. You already think like the office you are about to inherit." },
    "guile-":    { tag: "THE BLUNT INSTRUMENT", read: "You did not bother with subtlety. Power will offer you a great deal of it. Decline carefully." },
    "resolve+":  { tag: "THE PRINCIPLED", read: "You refused the money. You refused the shortcut. The desk you are inheriting is built entirely of shortcuts." },
    "resolve-":  { tag: "THE EXPEDIENT", read: "You took what worked, when it worked. Governance is the art of the expedient becoming permanent." },
    "defiance+": { tag: "THE SABOTEUR", read: "You broke the rules of the system you served. Now the rules are yours to break. Note the symmetry." },
    "defiance-": { tag: "THE LOYALIST", read: "You served the system even while fleeing it. It will be very glad to have you back, at the top." },
  };
  const arch = ARCH[top + sign] || { tag: "THE UNREADABLE", read: "Your patterns do not resolve cleanly. The system finds this either promising or alarming." };

  return { n, seeds, archetype: arch.tag, read: arch.read, dominant: top + sign };
}

// Bars to display in the transition, derived from normalized profile (0..100).
function profileBars(n) {
  const pct = (v) => Math.round(50 + 50 * v);
  return [
    { key: "nerve",    label: "Nerve",     hi: "reckless",   lo: "cautious",  v: pct(n.nerve) },
    { key: "mercy",    label: "Mercy",     hi: "for others", lo: "for self",  v: pct(n.mercy) },
    { key: "guile",    label: "Guile",     hi: "works seams", lo: "blunt",    v: pct(n.guile) },
    { key: "resolve",  label: "Resolve",   hi: "principled", lo: "expedient", v: pct(n.resolve) },
    { key: "defiance", label: "Defiance",  hi: "against",    lo: "compliant", v: pct(n.defiance) },
  ];
}

// Scale a delta object by difficulty (harsher = bigger swings).
function scaleDelta(d, mult) {
  const out = {};
  for (const k in d) out[k] = Math.round(d[k] * mult);
  return out;
}

// Detect an ending. Returns ending key or null.
function detectEnding(pillars, cardsLeft) {
  for (const k of ["military", "economy", "people", "foreign"]) {
    if (pillars[k] <= 0) return k + "_0";
    if (pillars[k] >= 100) return k + "_100";
  }
  if (cardsLeft <= 0) return "survived";
  return null;
}

// Algorithm commentary: occasionally surface a line tying a dictator choice
// back to who the player was during the escape. Returns a string or null.
function algorithmRead(choiceLog, flags, profileN) {
  const lib = [];
  if (/crush|clear|closed|example/i.test(choiceLog) && profileN.mercy > 0.2)
    lib.push("Curious. You spared strangers when you were powerless. You stop sparing them the moment it is affordable.");
  if (/amnesty|open|reform|met the/i.test(choiceLog) && profileN.mercy < -0.1)
    lib.push("You were ruthless in the sorting room. Mercy from the chair is cheaper, and you have noticed.");
  if (/election|honestly|real/i.test(choiceLog))
    lib.push("You who forged stamps to escape now ask others to trust a count. The system notes the irony without judging it.");
  if (/staged|cosmetic|paint|71%/i.test(choiceLog) && profileN.guile > 0.2)
    lib.push("You worked the seams as a clerk. You work them as a sovereign. Only the scale of the forgery has changed.");
  if (flags.contact_reported && /turn|courier|double|asset/i.test(choiceLog))
    lib.push("You sold a resistance cell once to buy your own safety. The technique scales. So does the cost.");
  if (flags.took_money && /loan|annex|patron/i.test(choiceLog))
    lib.push("You took Ferreira's money and learned that money is a hook. You are now the one holding the envelope.");
  return lib.length ? lib[Math.floor(Math.random() * lib.length)] : null;
}

Object.assign(window, {
  clamp, applyProfile, normalizeProfile, profileBars,
  scaleDelta, detectEnding, algorithmRead,
});
