#!/usr/bin/env node
'use strict';
// בדיקות לדלתות 1–18 + ScenarioDetector (ליבות טהורות, בלי רשת).
process.env.SC_TEST = '1';
const t = require('./dump-test.js').__test;
const assert = require('node:assert');

let pass = 0;
const ok = (name, cond) => { assert.ok(cond, name); console.log('PASS ' + name); pass++; };

(async () => {
  // Door 1: POLICY_KIT DSL compiles
  ok('Door1 POLICY_KIT has pricing/access/ranking', t.POLICY_KIT && t.POLICY_KIT.pricing && t.POLICY_KIT.access && t.POLICY_KIT.ranking);
  const kitP = t.compilePolicyDSL(t.POLICY_KIT.pricing);
  const kitOut = await t.xiClientEval(kitP.dag, { n: 25 });
  ok('Door1 pricing kit n=25 → promo 250', kitOut.output === 250);
  const kit10 = await t.xiClientEval(kitP.dag, { n: 10 });
  ok('Door1 pricing kit n=10 → base 120', kit10.output === 120);

  // Door 9 (legacy formula collapse)
  const simple = {
    nodes: {
      a: { value: 3 },
      b: { op: 'formula', args: { expr: 'x*x', vars: { x: { $ref: 'a' } } } },
    },
    output: 'b',
  };
  const ft = t.xiCollapseFormula(simple);
  ok('Door9collapse formula-tree', ft && ft.kind === 'formula-tree' && ft.expr.includes('3'));
  const full = t.xiCollapseFull(simple);
  ok('Door9collapse collapseFull marks collapsed', full.collapsed === true && full.light === true);

  // Door 11 DSL
  const dsl = [
    'policy livecalc',
    'in n = 25',
    'big = formula x*100 when x>20 where x<-n',
    'small = factorize n when x<=20 where x<-n',
    'out = coalesce big, small',
    'output out',
  ].join('\n');
  const compiled = t.compilePolicyDSL(dsl);
  ok('Door11 DSL compiles name+nodes', compiled.name === 'livecalc' && compiled.dag.nodes.big && compiled.dag.output === 'out');
  const dslOut = await t.xiClientEval(compiled.dag, {});
  ok('Door11 DSL eval default → 2500', dslOut.output === 2500);
  const dsl8 = await t.xiClientEval(compiled.dag, { n: 8 });
  ok('Door11 DSL eval n=8 → factorize', JSON.stringify(dsl8.output) === JSON.stringify([2, 2, 2]));

  // Door 4 nested
  const lib = { pricing: { dag: { nodes: { p: { value: 10 }, o: { op: 'formula', args: { expr: 'x*2', vars: { x: { $ref: 'p' } } } } }, output: 'o' } } };
  const wrap = { nodes: { x: { value: { $policy: 'pricing' } } }, output: 'x' };
  const expanded = await t.xiExpandNested(wrap, async (n) => lib[n]);
  const nestOut = await t.xiClientEval(expanded, {});
  ok('Door4 nested $policy expands and evals', nestOut.output === 20);

  // Door 10 / 13 state machine
  const spec = {
    initial: 'idle',
    transitions: [
      { from: 'idle', on: 'start', to: 'run', emit: 'go' },
      { from: 'run', on: 'tick', to: 'run', emit: 1 },
      { from: 'run', on: 'stop', to: 'idle', emit: 'done' },
    ],
  };
  const f1 = t.stateFold(spec, ['start', 'tick', 'tick', 'stop']);
  const f2 = t.stateFold(spec, ['start', 'tick', 'tick', 'stop']);
  ok('Door10/13 fold deterministic state', f1.state === 'idle' && f1.emitted.length === 4);
  ok('Door10/13 digest identical across clients', t.stateDigest(f1) === t.stateDigest(f2));
  const f3 = t.stateFold(spec, ['start', 'tick']);
  ok('Door10/13 different events → different digest', t.stateDigest(f1) !== t.stateDigest(f3));

  // Door 11 market + best shape
  const D = t.xiDigest(42);
  const pick = t.marketPick([
    { solver: 'A', digest: D, result: 42, price: 5, priority: 1 },
    { solver: 'B', digest: D, result: 42, price: 1, priority: 1 },
    { solver: 'C', digest: 'BAD', result: 0, price: 0, priority: 99 },
  ], { quorum: 2 });
  ok('Door11 market quorum+cheapest wins', pick.ok && pick.solver === 'B' && pick.result === 42);

  // Door 14 liveContext
  const ctx = t.liveContext({ lang: 'he', user: 'u1' });
  ok('Door14 liveContext has hour/lang/user', typeof ctx.hour === 'number' && ctx.lang === 'he' && ctx.user === 'u1');

  // Door 3/15 ScenarioDetector — policy swap + logic_fork
  const sd = new t.ScenarioDetector();
  const deg = sd.observe({ relaysUp: 1, phiAvg: 9, vitality: 0.2, scores: [0.1] });
  ok('Scenario relay_degraded → swap_degraded + policy:degraded', deg.scenario === 'relay_degraded' && deg.action === 'swap_degraded' && deg.activePolicy === 'policy:degraded');
  const hot = sd.observe({ relaysUp: 6, phiAvg: 0.5, vitality: 0.9, scores: [1, 1, 1, 1], nCached: 10, nComputed: 1 });
  ok('Scenario cache_hot → client_prefer + policy:full', hot.scenario === 'cache_hot' && hot.action === 'client_prefer' && hot.activePolicy === 'policy:full');
  const stale = sd.observe({ relaysUp: 5, phiAvg: 1, vitality: 0.8, scores: [1, 1], policyAgeMs: 9e9 });
  ok('Scenario policy_stale → republish', stale.scenario === 'policy_stale' && stale.action === 'republish_policy');
  const fork = sd.observe({ relaysUp: 6, phiAvg: 0, vitality: 1, scores: [1, 1], logicFork: true });
  ok('Scenario logic_fork → freeze_audit', fork.scenario === 'logic_fork' && fork.action === 'freeze_audit');

  // Door 7 identity + metaRoute
  const idDag = {
    nodes: {
      __authed: { value: 0 },
      guest: { op: 'formula', args: { expr: '1' }, when: { expr: 'a==0', vars: { a: { $ref: '__authed' } } } },
      member: { op: 'formula', args: { expr: '99' }, when: { expr: 'a==1', vars: { a: { $ref: '__authed' } } } },
      out: { coalesce: [{ $ref: 'member' }, { $ref: 'guest' }] },
    },
    output: 'out',
  };
  const g = await t.xiClientEval(idDag, { __authed: 0 });
  const m = await t.xiClientEval(idDag, { __authed: 1 });
  ok('Door7 identity branch guest', g.output === 1);
  ok('Door7 identity branch member', m.output === 99);
  const routeLib = {
    a: { dag: { nodes: { o: { value: 1 } }, output: 'o' } },
    b: { dag: { nodes: { o: { value: 2 } }, output: 'o' } },
  };
  const routed = t.metaRoute('vip', { vip: 'b', default: 'a' }, (n) => routeLib[n]);
  ok('Door7 metaRoute picks b for vip', routed.name === 'b' && routed.dag.nodes.o.value === 2);

  // Door 6 local digest verify
  const v1 = await t.xiClientEval(compiled.dag, { n: 25 });
  const v2 = await t.xiClientEval(compiled.dag, { n: 25 });
  ok('Door6 local digests match for same inputs', v1.dagDigest === v2.dagDigest);

  // Door 8 Roam time-travel
  const rr = new t.RoamResolver();
  const r0 = t.roamRecord('x', 'dag:aaa', 0, null, 1);
  const r1 = t.roamRecord('x', 'dag:bbb', 1, t.roamHash(r0), 2);
  const r2 = t.roamRecord('x', 'dag:ccc', 2, t.roamHash(r1), 3);
  ok('Door8 ingest chain', rr.ingest(r0) && rr.ingest(r1) && rr.ingest(r2));
  ok('Door8 tip is latest', rr.resolve() === 'dag:ccc');
  ok('Door8 atSeq(1) historical', rr.atSeq(1) === 'dag:bbb');
  ok('Door8 rollback tip rejected', rr.ingest(t.roamRecord('x', 'dag:evil', 1, null, 9)) === false && rr.resolve() === 'dag:ccc');

  // Door 9 context bind + Σ2 AAD seal
  const b1 = t.contextBind(42, { hour: 10, lang: 'he' });
  const b2 = t.contextBind(42, { hour: 11, lang: 'he' });
  ok('Door9 contextBind sealed differs by hour', b1.sealed !== b2.sealed && b1.ctxDigest !== b2.ctxDigest);
  ok('Door9 contextCheck same ctx', t.contextCheck(b1, { hour: 10, lang: 'he' }) === true);
  ok('Door9 contextCheck rejects other hour', t.contextCheck(b1, { hour: 11, lang: 'he' }) === false);
  t.ensureId(); t.deriveKeys();
  const sealed = t.contextSealPayload(Buffer.from('secret-hour'), { hour: 10 });
  const opened = t.contextOpenPayload(sealed.ct, { hour: 10 });
  ok('Door9 Σ2 AAD open same hour', opened.toString() === 'secret-hour');
  let aadFail = false;
  try { t.contextOpenPayload(sealed.ct, { hour: 11 }); } catch { aadFail = true; }
  ok('Door9 Σ2 AAD fails other hour', aadFail);

  // Door 13 consensus-of-computation / logic_fork
  const evA = await t.xiClientEval(compiled.dag, { n: 25 });
  const evB = await t.xiClientEval(compiled.dag, { n: 8 });
  const trA = t.branchTrace(evA);
  const trB = t.branchTrace(evB);
  ok('Door13 different inputs → different pathDigest', trA.pathDigest !== trB.pathDigest);
  const consOk = t.consensusBranches([
    { ...trA, author: 'p1' }, { ...trA, author: 'p2' },
  ], 2);
  ok('Door13 consensus agrees', consOk.ok && !consOk.fork);
  const consFork = t.consensusBranches([
    { ...trA, author: 'p1' }, { ...trB, author: 'p2' },
  ], 2);
  ok('Door13 logic_fork detected', consFork.fork === true);

  // Door 14 fragments
  const fragDag = {
    nodes: {
      a: { value: 6 },
      b: { op: 'formula', args: { expr: 'x+1', vars: { x: { $ref: 'a' } } } },
      c: { op: 'formula', args: { expr: 'y*2', vars: { y: { $ref: 'b' } } } },
    },
    output: 'c',
  };
  const frags = t.xiFragment(fragDag, 2);
  ok('Door14 xiFragment splits', frags.length === 2 && frags[0].ids.length >= 1);
  const d1 = 'aaaa', d2 = 'bbbb';
  ok('Door14 assemble digests deterministic', t.xiAssembleDigests([d1, d2]) === t.xiAssembleDigests([d1, d2]));

  // Door 15 scenario-native app select
  ok('Door15 scenarioAppSelect degraded', t.scenarioAppSelect('relay_degraded', { relay_degraded: 'degraded', default: 'full' }) === 'degraded');
  ok('Door15 scenarioAppSelect default', t.scenarioAppSelect('healthy_steady', { relay_degraded: 'degraded', default: 'full' }) === 'full');

  // Door 16 portable receipt
  const body = t.makeReceiptBody(v1.dagId, { n: 25 }, v1.output, { visitor: 'abc' });
  ok('Door16 receipt verifies', t.verifyReceiptBody(body, v1.output) === true);
  ok('Door16 receipt rejects wrong output', t.verifyReceiptBody(body, 999) === false);
  const tampered = { ...body, outputDigest: 'deadbeef' };
  ok('Door16 receipt rejects tamper', t.verifyReceiptBody(tampered, v1.output) === false);

  // Door 18 intent diff
  const dagA = { nodes: { a: { value: 1 }, b: { value: 2 } }, output: 'a' };
  const dagB = { nodes: { a: { value: 1 }, b: { value: 9 }, c: { value: 3 } }, output: 'c' };
  const diff = t.dagDiff(dagA, dagB);
  ok('Door18 dagDiff detects added/changed/out', diff.added.includes('c') && diff.changed.includes('b') && diff.outChanged);
  const applied = t.dagApplyDiff(dagA, diff, { b: dagB.nodes.b, c: dagB.nodes.c, __output: 'c' });
  ok('Door18 dagApplyDiff rebuilds', applied.output === 'c' && applied.nodes.c.value === 3 && applied.nodes.b.value === 9);

  // Door 12 Policy CDN marker in SDK string
  const sdk = t.buildWebSdk();
  ok('Door12 SDK boots skylive form/cdn', sdk.includes('skycloud-live-form') && sdk.includes('skylive.json') && sdk.includes('phi:health'));
  ok('Door1 SDK resolveLive + cooperate reputation', sdk.includes('resolveLive') && sdk.includes('reputation:'));

  console.log('\nALL ' + pass + ' DOORS TESTS PASSED');
})().catch((e) => { console.error('FAIL:', e && e.stack || e); process.exit(1); });
