/* ============================================================
   THE GREAT CLOUD — interactive pillars
   <MarketPanel/>   : live-feeling resource exchange
   <ScarcityMeter/> : the dynamic scarcity engine, animated
   <CraftBench/>    : crafting with controlled randomisation
   ============================================================ */
const { useState, useEffect, useRef, useCallback } = React;

const RARITY_MAP = Object.fromEntries(window.TGC.RARITIES.map((r) => [r.key, r]));
function fmt(n) { return n >= 1000 ? Math.round(n).toLocaleString('en-US') : n.toFixed(0); }
function rnd(a, b) { return a + Math.random() * (b - a); }

/* ---------------- Sparkline ---------------- */
function Spark({ points, color }) {
  if (!points || points.length < 2) return <svg className="spark" />;
  const min = Math.min(...points), max = Math.max(...points), span = max - min || 1;
  const w = 64, h = 26, pad = 3, step = w / (points.length - 1);
  const d = points.map((p, i) => {
    const x = i * step, y = pad + (h - pad * 2) * (1 - (p - min) / span);
    return `${i === 0 ? 'M' : 'L'}${x.toFixed(1)},${y.toFixed(1)}`;
  }).join(' ');
  return (
    <svg className="spark" viewBox={`0 0 ${w} ${h}`} preserveAspectRatio="none">
      <path d={d} style={{ stroke: color, opacity: 0.85 }} />
    </svg>
  );
}

/* ---------------- Market panel ---------------- */
function MarketPanel({ live = true }) {
  const init = window.TGC.MARKET.slice(0, 6);
  const [rows, setRows] = useState(() =>
    init.map((m) => ({ ...m, price: m.base, prev: m.base, hist: Array.from({ length: 16 }, () => m.base) })));

  useEffect(() => {
    if (!live) return;
    const id = setInterval(() => {
      setRows((rs) => rs.map((r) => {
        const drift = (r.base - r.price) * 0.05;
        const shock = (Math.random() - 0.5) * 2 * r.vol * r.base;
        let next = Math.max(1, Math.round((r.price + drift + shock) * 100) / 100);
        return { ...r, prev: r.price, price: next, hist: r.hist.concat(next).slice(-16) };
      }));
    }, 1500);
    return () => clearInterval(id);
  }, [live]);

  return (
    <div className="market reveal">
      <div className="market-top">
        <span>Global Exchange · indicative base values</span>
        <span className="live"><i className="dot" />{live ? 'simulated' : 'paused'}</span>
      </div>
      {rows.map((r) => {
        const rar = RARITY_MAP[r.rarity];
        const delta = ((r.price - r.base) / r.base) * 100;
        const up = r.price >= r.prev;
        return (
          <div className="market-row" key={r.name}>
            <span className="item"><i className="swatch" style={{ background: rar.color, color: rar.color }} />{r.name}</span>
            <span className="price">{fmt(r.price)}<span className="u">sh</span></span>
            <span className={`delta ${delta >= 0 ? 'up' : 'dn'}`}>{delta >= 0 ? '▲' : '▼'} {Math.abs(delta).toFixed(1)}%</span>
            <Spark points={r.hist} color={up ? '#53d68a' : '#ff6b78'} />
          </div>
        );
      })}
    </div>
  );
}

/* ---------------- Dynamic scarcity meter ----------------
   Shows target supply (1 per N active players) vs current supply,
   and how the drop/craft probability responds. Interactive slider. */
function ScarcityMeter() {
  const SC = window.TGC.SCARCITY || {};
  const perTarget = SC.legendaryPerActive || 1000;  // real AD-062 baseline: 1 legendary per N active
  const [players, setPlayers] = useState(8400);     // active players (the slider simulates this)
  const target = Math.max(1, Math.round(players / perTarget));
  const [supply, setSupply] = useState(() => Math.round(target * 0.6));

  // supply drifts toward target as the engine adjusts probability
  useEffect(() => {
    const id = setInterval(() => {
      setSupply((s) => {
        const gap = target - s;
        const step = Math.sign(gap) * Math.max(1, Math.round(Math.abs(gap) * 0.18));
        const noise = Math.round(rnd(-1, 1) * (target * 0.03));
        return Math.max(0, s + step + noise);
      });
    }, 900);
    return () => clearInterval(id);
  }, [target]);

  const ratio = supply / target;            // <1 under-supplied, >1 over
  const pct = Math.min(140, ratio * 100);
  const boosting = ratio < 0.98;
  const damping = ratio > 1.02;
  const probState = boosting ? 'boosting' : damping ? 'damping' : 'on target';
  const probColor = boosting ? '#53d68a' : damping ? '#ff6b78' : '#4da6ff';

  return (
    <div className="scarcity reveal">
      <div className="market-top">
        <span>Dynamic Scarcity Engine</span>
        <span className="live" style={{ color: probColor }}><i className="dot" />{probState}</span>
      </div>
      <div className="sc-body">
        <div className="sc-stat">
          <span className="k">Target rarity</span>
          <span className="v">1 <span className="u">Legendary per {perTarget.toLocaleString()} active</span></span>
        </div>
        <div className="sc-bar-wrap">
          <div className="sc-bar">
            <div className="sc-target" />
            <div className="sc-fill" style={{ width: `${Math.min(100, (pct / 140) * 100)}%`, background: probColor }} />
          </div>
          <div className="sc-bar-legend">
            <span>supply <b style={{ color: probColor }}>{supply}</b> / target <b>{target}</b></span>
            <span className="sc-target-tick">target</span>
          </div>
        </div>
        <div className="sc-grid">
          <div className="sc-stat sm"><span className="k">Active players</span><span className="v">{players.toLocaleString()}</span></div>
          <div className="sc-stat sm"><span className="k">Drop probability</span><span className="v" style={{ color: probColor }}>{boosting ? '▲ rising' : damping ? '▼ falling' : '→ held'}</span></div>
        </div>
        <label className="sc-slider">
          <span>Simulate active population</span>
          <input type="range" min="1000" max="50000" step="500" value={players}
            onChange={(e) => setPlayers(parseInt(e.target.value, 10))} />
        </label>
        <p className="sc-note">Supply is evaluated <b>globally</b>, across every region — so rarity is preserved without ever going extinct.</p>
      </div>
    </div>
  );
}

/* ---------------- Crafting bench ----------------
   Real recipes + the real four-roll outcome model (quality -> stats -> appearance
   -> rarity), ported from shared/src/sim/crafting.ts and fed by window.TGC_LIVE.
   Same recipe, different result every craft — with the occasional rarity proc. */
const CRAFT = window.TGC.CRAFT || {};
const QUALITY_BY_KEY = Object.fromEntries((CRAFT.qualityGrades || []).map((q) => [q.key, q]));
const CRAFT_RARITIES = CRAFT.rarities || ['common', 'uncommon', 'rare', 'epic', 'legendary'];

// Weighted pick over the recipe's real quality weights (roll 1, neutral-input case).
function pickQuality(weights) {
  const entries = Object.entries(weights || {}).filter(([, w]) => w > 0);
  const total = entries.reduce((s, [, w]) => s + w, 0);
  if (total <= 0) return (CRAFT.qualityGrades[0] && CRAFT.qualityGrades[0].key) || 'standard';
  let x = Math.random() * total;
  for (const [k, w] of entries) { if (x < w) return k; x -= w; }
  return entries[entries.length - 1][0];
}

function craftOutcome(recipe) {
  const out = recipe.output || {};
  const quality = pickQuality(recipe.qualityWeights);
  const qMeta = QUALITY_BY_KEY[quality] || { label: quality, color: '#c7d2dc', mult: 1 };
  // Roll 2 — stats: base x quality multiplier x (1 +/- statVariance), clamped to the tier envelope.
  const budget = (CRAFT.powerEnvelope || {})[out.tier] || {};
  const variance = recipe.statVariance == null ? 0.1 : recipe.statVariance;
  const stats = Object.entries(out.baseStats || {}).map(([k, b]) => {
    const factor = 1 + (Math.random() * 2 - 1) * variance;
    let v = Math.round(b * qMeta.mult * factor);
    if (budget[k] != null) v = Math.max(0, Math.min(v, budget[k]));
    return { k, v };
  });
  // Roll 3 — appearance, from the recipe's pool.
  const pool = recipe.appearancePool && recipe.appearancePool.length ? recipe.appearancePool : ['plain'];
  const appearance = pool[Math.floor(Math.random() * pool.length)];
  // Roll 4 — rarity proc: base rarity, bounded single-step chance up to the recipe's maxRarity.
  let rarity = out.rarity || 'common';
  const proc = recipe.rarityProc;
  if (proc && proc.maxRarity) {
    const bi = CRAFT_RARITIES.indexOf(rarity), mi = CRAFT_RARITIES.indexOf(proc.maxRarity);
    const chance = CRAFT.rarityProcChance == null ? 0.08 : CRAFT.rarityProcChance;
    if (mi > bi && Math.random() < chance) rarity = CRAFT_RARITIES[Math.min(bi + 1, mi)];
  }
  const capFirst = (s) => s.charAt(0).toUpperCase() + s.slice(1);
  return {
    recipe, quality, qMeta, rarity, procced: rarity !== (out.rarity || 'common'),
    appearance, stats, name: `${capFirst(appearance)} ${out.name}`, seed: seedHash(),
  };
}
function seedHash() {
  return Array.from({ length: 6 }, () => '0123456789ABCDEF'[Math.floor(Math.random() * 16)]).join('');
}

function CraftBench() {
  const recipes = (window.TGC.RECIPES || []).slice(0, 10);
  const [recipeIdx, setRecipeIdx] = useState(0);
  const [phase, setPhase] = useState('idle');   // idle | crafting | done
  const [out, setOut] = useState(null);
  const [count, setCount] = useState(0);
  const timers = useRef([]);
  const recipe = recipes[recipeIdx];

  const clear = () => { timers.current.forEach(clearTimeout); timers.current = []; };
  useEffect(() => () => clear(), []);

  const craft = useCallback(() => {
    if (phase === 'crafting' || !recipe) return;
    clear();
    setPhase('crafting');
    const final = craftOutcome(recipe);
    let delay = 70, elapsed = 0; const stop = 1050;
    const tick = () => {
      setOut(craftOutcome(recipe));
      elapsed += delay; delay *= 1.18;
      if (elapsed < stop) timers.current.push(setTimeout(tick, delay));
      else timers.current.push(setTimeout(() => { setOut(final); setPhase('done'); setCount((c) => c + 1); }, delay));
    };
    tick();
  }, [phase, recipe]);

  if (!recipe) return null;
  const qc = out ? out.qMeta.color : null;             // orb tints to the rolled quality
  const procRar = out && out.procced ? RARITY_MAP[out.rarity] : null;
  const inputLine = recipe.inputs.map((i) => `${i.quantity}x ${i.name}`).join(' · ');

  const burst = phase === 'done'
    ? Array.from({ length: 16 }).map((_, i) => {
        const ang = (i / 16) * Math.PI * 2, dist = 70 + Math.random() * 40;
        return <i key={i} style={{ '--bx': `${Math.cos(ang) * dist}px`, '--by': `${Math.sin(ang) * dist}px`, animationDelay: `${Math.random() * 0.05}s` }} />;
      })
    : null;

  return (
    <div className={`roll-card ${phase === 'crafting' ? 'rolling' : phase === 'done' ? 'landed' : 'idle'}`} style={qc ? { '--rc': qc } : {}}>
      <div className="rc-head">
        <span>Crafting Bench · live recipes</span>
        <span>{count > 0 ? `craft #${count}` : recipe.discipline}</span>
      </div>

      <div className="recipe-pick">
        {recipes.map((r, i) => (
          <button key={r.id} className={`rp ${i === recipeIdx ? 'on' : ''}`}
            onClick={() => { if (phase !== 'crafting') { setRecipeIdx(i); setOut(null); setPhase('idle'); } }}
            title={`${r.name} — ${r.discipline}`}>{r.glyph}</button>
        ))}
      </div>

      <div className="roll-stage">
        <div className="roll-orb">
          <div className="roll-burst">{burst}</div>
          <span className="glyph">{recipe.glyph}</span>
        </div>
        <div className="roll-name">{out ? out.name : recipe.output.name}</div>
        <div className="roll-rarity">
          {phase === 'idle' ? `${recipe.discipline} · rank ${recipe.masteryRank}`
            : out ? <span>{out.qMeta.label} quality{procRar ? <b style={{ color: procRar.color }}> · {procRar.label}!</b> : ''}</span> : ''}
        </div>
        {phase === 'done' && out && out.stats.length ? (
          <div className="craft-stats">
            {out.stats.map((s) => (<span className="cs" key={s.k}><b style={{ color: qc }}>+{s.v}</b> {s.k}</span>))}
          </div>
        ) : (
          <div className="roll-flavor">
            {phase === 'crafting' ? 'rolling quality, stats, finish…'
              : phase === 'done' ? `crafted from ${inputLine}`
              : `${inputLine} → 1x ${recipe.output.name}`}
          </div>
        )}
      </div>

      <div className="roll-foot">
        <span className="seed">seed&nbsp;0x{out ? out.seed : '——————'}</span>
        <span className="seed">{phase === 'done' && out ? `${out.qMeta.label}${out.procced ? ` · ${procRar.label}` : ''}` : `${Object.keys(recipe.qualityWeights).length} quality tiers`}</span>
      </div>
      <button className="btn roll-btn" onClick={craft} disabled={phase === 'crafting'}>
        {phase === 'crafting' ? 'crafting…' : phase === 'done' ? 'Craft again' : 'Craft this recipe'}
      </button>
    </div>
  );
}

Object.assign(window, { MarketPanel, ScarcityMeter, CraftBench, Spark });
