// Consensus gate visualization — 25 named verifiers voting on an order in real time.
// Auto-cycles through 5 prepared orders that include both ALLOWS and REFUSALS.
// Centerpiece interactive of the landing page.

const TX_ORDERS = [
  {
    sym: 'AAPL', side: 'BUY', qty: 100, price: 205.42, type: 'MARKET',
    notional: 20542, broker: 'alpaca',
    votes: ['y','y','y','y','y','y','y','y','y','y','y','y','y','n','y','y','y','y','a','y','y','y','y','y','y'],
    latency: 187, proof: 'a3b2-9c1f',
    reason: 'All 25 verifiers passed · clean signal',
  },
  {
    sym: 'TSLA', side: 'SELL', qty: 1000, price: 287.10, type: 'MARKET',
    notional: 287100, broker: 'alpaca',
    votes: ['y','y','n','y','y','y','n','y','y','y','y','n','y','y','y','y','n','a','y','y','n','y','y','n','y'],
    latency: 211, proof: '4e8a-1d77',
    reason: 'Borderline · 17/25 verified · 7 flagged for caution',
  },
  {
    sym: 'GME', side: 'BUY', qty: 5000, price: 25.50, type: 'LIMIT',
    notional: 127500, broker: 'alpaca',
    votes: ['n','y','n','n','y','n','y','n','y','n','n','y','n','y','n','y','n','a','y','n','y','n','y','n','y'],
    latency: 245, proof: 'c8f3-7b22',
    reason: '14 verifiers flagged · low-float meme + 23-hour vol',
  },
  {
    sym: 'NVDA', side: 'BUY', qty: 10, price: 1147.88, type: 'MARKET',
    notional: 11479, broker: 'moomoo',
    votes: ['y','y','y','y','y','y','y','y','y','y','y','y','y','y','y','y','y','y','y','y','y','y','y','y','y'],
    latency: 142, proof: 'f1a8-2e09',
    reason: 'Unanimous · all 25 verifiers agree',
  },
  {
    sym: 'SPY', side: 'SELL', qty: 2, price: 0, type: 'LIMIT',
    notional: 0, broker: 'alpaca',
    votes: ['y','n','y','n','y','y','n','y','n','y','n','y','n','y','y','n','y','y','n','a','y','n','y','n','y'],
    latency: 198, proof: '0d2c-5fb1',
    reason: 'Stale quote · limit price missing · below the conviction bar',
  },
];

function decisionFor(votes, threshold = 0.68) {
  const yes = votes.filter(v => v === 'y').length;
  const no = votes.filter(v => v === 'n').length;
  const ab = votes.filter(v => v === 'a').length;
  const ratio = yes / votes.length;
  return {
    yes, no, ab,
    ratio,
    decision: ratio >= threshold ? 'allow' : 'refuse',
    pass: ratio >= threshold,
    needed: Math.ceil(threshold * votes.length),
  };
}

function ConsensusGate() {
  const [idx, setIdx] = React.useState(0);
  const [shown, setShown] = React.useState(0);    // # of agents resolved
  const [latency, setLatency] = React.useState(0); // ms counter
  const [pinned, setPinned] = React.useState(false);
  const order = TX_ORDERS[idx];
  const d = decisionFor(order.votes);

  // Sequence: agents vote in over ~1.4s, then dwell ~3s, advance
  React.useEffect(() => {
    setShown(0); setLatency(0);
    const VOTE_INTERVAL = Math.floor(order.latency / 25);
    const timers = [];
    // tick latency
    const lt = setInterval(() => setLatency(l => Math.min(order.latency, l + 8)), 16);
    timers.push(() => clearInterval(lt));
    // stagger reveals
    for (let i = 1; i <= 25; i++) {
      const t = setTimeout(() => setShown(i), VOTE_INTERVAL * i + 200);
      timers.push(() => clearTimeout(t));
    }
    // dwell then advance (unless pinned)
    if (!pinned) {
      const adv = setTimeout(() => setIdx((idx + 1) % TX_ORDERS.length), VOTE_INTERVAL * 25 + 200 + 3500);
      timers.push(() => clearTimeout(adv));
    }
    return () => timers.forEach(fn => fn());
  }, [idx, pinned]);

  // Counts visible so far
  const visibleVotes = order.votes.slice(0, shown);
  const ys = visibleVotes.filter(v => v === 'y').length;
  const ns = visibleVotes.filter(v => v === 'n').length;
  const as = visibleVotes.filter(v => v === 'a').length;
  const finalShown = shown === 25;
  const headerKind = !finalShown ? 'pending' : d.decision;

  // Styles (component-scoped names so they don't collide)
  const gateStyles = {
    card: {
      background: T.ink, color: T.textInv,
      border: `1px solid ${T.inkBorder}`,
      fontFamily: GEIST, position: 'relative',
    },
    head: {
      padding: '14px 22px', borderBottom: `1px solid ${T.inkBorder}`,
      display: 'flex', alignItems: 'center', justifyContent: 'space-between',
    },
    body: { padding: '22px 22px 24px' },
    orderRow: {
      display: 'grid', gridTemplateColumns: 'auto auto 1fr auto auto', gap: 24,
      padding: '14px 0', borderBottom: `1px solid ${T.inkBorder}`,
      alignItems: 'baseline',
    },
    field: { display: 'flex', flexDirection: 'column', gap: 4 },
    val: {
      fontFamily: GMONO, fontWeight: 500, fontSize: 16,
      color: T.textInv, letterSpacing: 0.2, lineHeight: 1,
    },
    valBig: {
      fontFamily: GMONO, fontWeight: 500, fontSize: 22,
      color: T.textInv, letterSpacing: 0.4, lineHeight: 1,
    },
    bar: {
      height: 6, background: 'rgba(244,244,240,0.06)', position: 'relative',
      marginTop: 14, marginBottom: 8,
    },
    barFill: {
      position: 'absolute', left: 0, top: 0, bottom: 0,
      transition: 'width .15s linear',
    },
    threshold: {
      position: 'absolute', top: -6, bottom: -6,
      borderLeft: `1px dashed ${T.caution}`,
    },
    grid: {
      display: 'grid', gridTemplateColumns: 'repeat(13, 1fr)', gap: 8,
      marginTop: 18, marginBottom: 4,
    },
    dot: (v, idx_) => ({
      width: '100%', aspectRatio: '1 / 1',
      background: v === 'y' ? T.allow : v === 'n' ? T.refuse : T.caution,
      opacity: idx_ < shown ? 1 : 0.08,
      transition: 'opacity .12s ease, transform .25s cubic-bezier(.2,.9,.3,1.2)',
      transform: idx_ < shown ? 'scale(1)' : 'scale(0.6)',
      borderRadius: 2,
    }),
    headers: {
      marginTop: 18, paddingTop: 16, borderTop: `1px solid ${T.inkBorder}`,
      display: 'flex', flexDirection: 'column', gap: 6,
    },
    headerRow: { display: 'grid', gridTemplateColumns: '220px 1fr', gap: 16 },
    tabs: {
      display: 'flex', marginTop: 18, paddingTop: 14, borderTop: `1px solid ${T.inkBorder}`,
    },
    tab: (active) => ({
      flex: 1, padding: '8px 4px 0', background: 'transparent', border: 'none',
      borderTop: active ? `2px solid ${T.allow}` : '2px solid transparent',
      marginTop: -15, cursor: 'pointer', color: 'inherit', textAlign: 'left',
      transition: 'all .15s ease',
    }),
  };

  return (
    <div style={gateStyles.card}>
      <CornerMark where="tl" color={T.inkBorder}/>
      <CornerMark where="tr" color={T.inkBorder}/>
      <CornerMark where="bl" color={T.inkBorder}/>
      <CornerMark where="br" color={T.inkBorder}/>

      {/* Head row */}
      <div style={gateStyles.head}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 14 }}>
          <Bracket color={T.allow}>NEW ORDER TICKET</Bracket>
          <Mono color={T.muteInv}>TICKET · {order.proof}</Mono>
        </div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
          <Pulse color={finalShown ? (d.pass ? T.allow : T.refuse) : T.caution} size={6}/>
          <Mono color={T.muteInv}>PRE-TRADE VERIFICATION</Mono>
        </div>
      </div>

      <div style={gateStyles.body}>
        {/* Order details */}
        <div style={gateStyles.orderRow}>
          <div style={gateStyles.field}>
            <Mono color={T.muteInv}>SYMBOL</Mono>
            <span style={gateStyles.valBig}>{order.sym}</span>
          </div>
          <div style={gateStyles.field}>
            <Mono color={T.muteInv}>SIDE</Mono>
            <span style={{ ...gateStyles.val, color: order.side === 'BUY' ? T.allow : T.caution }}>{order.side}</span>
          </div>
          <div style={gateStyles.field}>
            <Mono color={T.muteInv}>VALUE</Mono>
            <span style={gateStyles.val}>
              {order.notional > 0 ? '$' + order.notional.toLocaleString() : 'Quote pending'}
            </span>
          </div>
          <div style={gateStyles.field}>
            <Mono color={T.muteInv}>SHARES · ORDER</Mono>
            <span style={gateStyles.val}>{order.qty.toLocaleString()} · {order.type}</span>
          </div>
          <div style={gateStyles.field}>
            <Mono color={T.muteInv}>BROKER</Mono>
            <span style={gateStyles.val}>{order.broker}</span>
          </div>
        </div>

        {/* Vote progress */}
        <div style={{ marginTop: 24, display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 16 }}>
            <Mono color={T.muteInv} weight={500}>25 VERIFIERS · CHECKING</Mono>
            <span style={{
              fontFamily: GMONO, fontSize: 13, color: T.allow, letterSpacing: 0.5,
            }}>{ys}<span style={{ color: T.muteInv }}> / 25</span></span>
            {ns > 0 && <span style={{ fontFamily: GMONO, fontSize: 13, color: T.refuse }}>· {ns} no</span>}
            {as > 0 && <span style={{ fontFamily: GMONO, fontSize: 13, color: T.caution }}>· {as} abstain</span>}
          </div>
          <Mono color={T.muteInv}>BAR · 17 OF 25 · 68%</Mono>
        </div>

        {/* Segmented bar — 25 cells, one per verifier. Cells fill in left-to-right
            as votes resolve. A vertical PASS BAR line sits between cells 17 and 18,
            with a labeled flag above. Universal vote-count pattern. */}
        <SegBar
          votes={order.votes}
          shown={shown}
          ys={ys}
          ns={ns}
          as={as}
          finalShown={finalShown}
          pass={d.pass}
          ratio={d.ratio}
        />

        {/* Decision + latency */}
        <div style={{
          marginTop: 22, display: 'flex', alignItems: 'center', justifyContent: 'space-between',
          opacity: finalShown ? 1 : 0.45, transition: 'opacity .3s ease',
        }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 16 }}>
            <Decision kind={headerKind} size="lg"/>
            <Mono color={T.muteInv}>{order.reason}</Mono>
          </div>
          <div style={{ display: 'flex', alignItems: 'baseline', gap: 6 }}>
            <span style={{ fontFamily: GMONO, fontSize: 26, color: T.textInv, fontWeight: 500, letterSpacing: 0.4 }}>
              {String(latency).padStart(3, '0')}
            </span>
            <Mono color={T.muteInv}>MS</Mono>
          </div>
        </div>

        {/* Pre-trade ticket */}
        <div style={gateStyles.headers}>
          <Mono color={T.allow} weight={500}>PRE-TRADE RECEIPT</Mono>
          {[
            ['Verdict',       (d.decision === 'allow' ? 'CLEARED' : 'BLOCKED')],
            ['Agreement',    (d.ratio * 100).toFixed(2) + '%'],
            ['Verifier count', `${ys} of 25`],
            ['Decision time', latency + ' ms'],
            ['Receipt ID',    order.proof + '-' + Math.random().toString(36).slice(2, 10)],
          ].map(([k, v]) => (
            <div key={k} style={gateStyles.headerRow}>
              <span style={{ fontFamily: GMONO, fontSize: 11, color: T.muteInv, letterSpacing: 0.2 }}>{k}</span>
              <span style={{
                fontFamily: GMONO, fontSize: 11.5, letterSpacing: 0.3,
                color: k === 'Verdict' && v === 'CLEARED' ? T.allow
                     : k === 'Verdict' && v === 'BLOCKED' ? T.refuse
                     : T.textInv,
                fontWeight: k === 'Verdict' ? 600 : 500,
              }}>{v}</span>
            </div>
          ))}
        </div>

        {/* Order tabs */}
        <div style={gateStyles.tabs}>
          {TX_ORDERS.map((o, i) => {
            const sub = decisionFor(o.votes);
            return (
              <button key={o.sym} style={gateStyles.tab(i === idx)}
                onClick={() => { setPinned(true); setIdx(i); }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                  <span style={{
                    fontFamily: GMONO, fontSize: 12, fontWeight: 500, letterSpacing: 0.5,
                    color: i === idx ? T.textInv : T.muteInv,
                  }}>{o.sym}</span>
                  <span style={{
                    width: 6, height: 6, background: sub.pass ? T.allow : T.refuse,
                    opacity: i === idx ? 1 : 0.5,
                  }}/>
                </div>
              </button>
            );
          })}
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { ConsensusGate, TX_ORDERS, decisionFor });

// ── SegBar — 25-cell verifier vote bar with a hard PASS BAR line ─
function SegBar({ votes, shown, ys, ns, as, finalShown, pass, ratio }) {
  // Position of the PASS BAR boundary: exactly between cell 17 and 18.
  // With 25 equal cells the boundary sits at 17/25 of the bar width.
  const passBarPct = (17 / 25) * 100;
  const pct = Math.round(ratio * 100);

  return (
    <div style={{ marginTop: 18 }}>
      {/* HEADER ROW — running count on the left, verdict stamp on the right */}
      <div style={{
        display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between',
        marginBottom: 16, gap: 16, minHeight: 56,
      }}>
        <div>
          <div style={{
            display: 'inline-flex', alignItems: 'baseline', gap: 8,
            fontFamily: GMONO, fontWeight: 500, letterSpacing: 0.4,
            color: finalShown ? (pass ? T.allow : T.refuse) : T.textInv,
            transition: 'color .3s ease', lineHeight: 1,
          }}>
            <span style={{ fontSize: 36 }}>{ys}</span>
            <span style={{ fontSize: 18, color: T.muteInv, fontWeight: 400 }}>of 25</span>
          </div>
          <Mono color={T.muteInv} size={10.5} style={{ display: 'block', marginTop: 6, letterSpacing: 1 }}>
            VERIFIERS AGREE · {pct}%
            {ns > 0 && <span style={{ color: T.refuse, marginLeft: 8 }}>· {ns} NO</span>}
            {as > 0 && <span style={{ color: T.caution, marginLeft: 8 }}>· {as} ABSTAIN</span>}
          </Mono>
        </div>

        <div style={{
          display: 'inline-flex', alignItems: 'center', gap: 10,
          padding: '8px 14px',
          background: finalShown
            ? (pass ? 'rgba(45,216,129,0.10)' : 'rgba(255,86,86,0.10)')
            : 'transparent',
          border: `1px solid ${finalShown ? (pass ? T.allow : T.refuse) : T.inkBorder}`,
          opacity: finalShown ? 1 : 0.55,
          transition: 'all .3s ease',
        }}>
          <span style={{
            display: 'inline-block', width: 10, height: 10,
            background: finalShown ? (pass ? T.allow : T.refuse) : T.muteInv,
          }}/>
          <span style={{
            fontFamily: GMONO, fontSize: 12, fontWeight: 600, letterSpacing: 1.4,
            color: finalShown ? (pass ? T.allow : T.refuse) : T.muteInv,
            textTransform: 'uppercase',
          }}>
            {!finalShown ? 'Verifying' : (pass ? '✓ Cleared' : '✗ Refused')}
          </span>
        </div>
      </div>

      {/* PASS BAR flag — floats above the bar at the 17/25 boundary */}
      <div style={{ position: 'relative', height: 30, marginBottom: 6 }}>
        <div style={{
          position: 'absolute', top: 0, left: `${passBarPct}%`,
          transform: 'translateX(-50%)',
          display: 'flex', flexDirection: 'column', alignItems: 'center',
          pointerEvents: 'none',
        }}>
          <div style={{
            padding: '3px 9px', background: T.ink,
            border: `1px solid ${T.caution}`,
          }}>
            <span style={{
              fontFamily: GMONO, fontSize: 9.5, fontWeight: 600, letterSpacing: 1.2,
              color: T.caution, textTransform: 'uppercase',
            }}>PASS BAR · 17 OF 25</span>
          </div>
          {/* tick connecting flag to bar */}
          <div style={{ width: 1, height: 6, background: T.caution }}/>
        </div>
      </div>

      {/* SEGMENTED BAR — 25 cells, fill in left-to-right */}
      <div style={{ position: 'relative' }}>
        <div style={{
          display: 'grid', gridTemplateColumns: 'repeat(25, 1fr)', gap: 2,
          background: 'rgba(244,244,240,0.02)', padding: 2,
          border: `1px solid ${T.inkBorder}`,
        }}>
          {votes.map((v, i) => {
            const visible = i < shown;
            const baseColor = v === 'y' ? T.allow : v === 'n' ? T.refuse : T.caution;
            // Pull agent metadata from council-data (loaded ahead of this script).
            const ag = (typeof AGENTS !== 'undefined') ? AGENTS[i] : null;
            const specLabel = ag ? (SPEC[ag.specialty]?.label || '') : '';
            const voteLabel = !visible ? 'pending'
                            : v === 'y' ? 'agrees'
                            : v === 'n' ? 'disagrees'
                            : 'abstains';
            const tip = ag
              ? `#${String(ag.id).padStart(2,'0')} · Agent ${ag.name} · ${specLabel} · ${voteLabel}`
              : `Verifier ${i + 1} · ${voteLabel}`;
            return (
              <div key={i}
                title={tip}
                style={{
                  height: 34, position: 'relative',
                  background: visible ? baseColor : 'rgba(244,244,240,0.05)',
                  transition: 'background .18s ease',
                  display: 'flex', alignItems: 'center', justifyContent: 'center',
                  cursor: 'help',
                }}>
                {/* Pre-fill tick — subtle counter so you know which cell is up next */}
                {!visible && (
                  <span style={{
                    fontFamily: GMONO, fontSize: 9, color: 'rgba(244,244,240,0.18)',
                  }}>{i + 1}</span>
                )}
              </div>
            );
          })}
        </div>

        {/* Hard vertical PASS BAR line — sits between cells 17 and 18 */}
        <div style={{
          position: 'absolute', top: -4, bottom: -4,
          left: `${passBarPct}%`, marginLeft: -1, width: 2,
          background: T.caution, opacity: 0.95, pointerEvents: 'none',
        }}/>
        {/* Soft glow on the pass-side of the bar once cleared */}
        {finalShown && pass && (
          <div style={{
            position: 'absolute', top: 0, bottom: 0,
            left: `${passBarPct}%`, right: 0,
            background: `linear-gradient(90deg, rgba(45,216,129,0.10), transparent 60%)`,
            pointerEvents: 'none',
            animation: 'pulse-soft 2.2s ease-out infinite',
          }}/>
        )}
      </div>

      {/* TICK ROW — verifier indices, with 17 highlighted */}
      <div style={{
        marginTop: 8,
        display: 'grid', gridTemplateColumns: 'repeat(25, 1fr)',
      }}>
        {Array.from({ length: 25 }).map((_, i) => {
          const n = i + 1;
          const showLabel = n === 1 || n === 17 || n === 25 || n % 5 === 0;
          return (
            <div key={i} style={{
              textAlign: 'center',
              fontFamily: GMONO, fontSize: 9, letterSpacing: 0.4,
              color: n === 17 ? T.caution : T.muteInv,
              fontWeight: n === 17 ? 600 : 400,
            }}>
              {showLabel ? n : ''}
            </div>
          );
        })}
      </div>

      {/* LEGEND */}
      <div style={{
        marginTop: 14, paddingTop: 12, borderTop: `1px solid ${T.inkBorder}`,
        display: 'flex', alignItems: 'center', gap: 18, flexWrap: 'wrap',
      }}>
        <LegendChip color={T.allow}   label="agrees"/>
        <LegendChip color={T.refuse}  label="disagrees"/>
        <LegendChip color={T.caution} label="abstains"/>
        <span style={{ width: 1, height: 14, background: T.inkBorder, margin: '0 4px' }}/>
        <span style={{
          display: 'inline-flex', alignItems: 'center', gap: 8,
          fontFamily: GEIST, fontSize: 12, color: T.muteInv, letterSpacing: -0.1,
        }}>
          <span style={{ width: 14, height: 2, background: T.caution }}/>
          <span>Pass bar — clears at 17 of 25 (68%)</span>
        </span>
      </div>
    </div>
  );
}

function LegendChip({ color, label }) {
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 8,
      fontFamily: GEIST, fontSize: 12, color: T.muteInv, letterSpacing: -0.1,
    }}>
      <span style={{ width: 10, height: 10, background: color }}/>
      <span>One verifier {label}</span>
    </span>
  );
}
