import test from 'node:test';
import assert from 'node:assert/strict';
import { createSeedWorkspace, validateWorkspace, verifyWorkspace, normalizeValue, addObject, addRepresentation, applyReconciliation, exportReceiptBundle, verifyReceiptChain, resolveException, completeContinuation } from '../coherence/core.js';
import { WorkspaceHistory } from '../coherence/history.js';

test('decimal comparison preserves precision beyond JavaScript numbers', () => {
  assert.notEqual(normalizeValue('9007199254740993','decimal'),normalizeValue('9007199254740992','decimal'));
  assert.notEqual(normalizeValue('0.100000000000000001','decimal'),normalizeValue('0.1','decimal'));
  assert.equal(normalizeValue('$001.000', 'usd'), '#1');
  assert.equal(normalizeValue('-0.00', 'decimal'), '#0');
});
test('import validates structure, unique identities, and cross-object references', async () => {
  const base=await createSeedWorkspace();
  for (const mutate of [w=>w.objects.push(structuredClone(w.objects[0])),w=>w.evidence[0].objectId='missing',w=>w.objects[0].representations[0].writable='false',w=>w.continuations[0].events={},w=>w.exceptions[0].representationId='absent']) {
    const w=structuredClone(base); mutate(w); assert.throws(()=>validateWorkspace(w));
  }
  const w=JSON.parse(JSON.stringify(base)); w.objects[0].representations[0].fields=JSON.parse('{"__proto__":"x"}');
  assert.throws(()=>validateWorkspace(w),/Unsupported field/);
});
test('evidence tampering is rejected even when the receipt chain still matches', async () => {
  const w=await createSeedWorkspace(); w.evidence[0].excerpt='altered';
  assert.equal((await verifyReceiptChain(w.receipts)).valid,true);
  await assert.rejects(()=>verifyWorkspace(w),/Evidence digest mismatch/);
});
test('receipt exports preserve the full chain across multiple objects', async () => {
  let w=await createSeedWorkspace(); w=addObject(w,{label:'Other object',externalKey:'other'}).workspace;
  w=addRepresentation(w,{system:'A',recordKey:'a',fields:{amount:'1'},writable:true}).workspace;
  w=addRepresentation(w,{system:'B',recordKey:'b',fields:{amount:'2'},writable:true}).workspace;
  w=(await applyReconciliation(w,{field:'amount',targetValue:'1',actor:'operator',reason:'checked'})).workspace;
  const bundle=await exportReceiptBundle(w);
  assert.equal(bundle.receipts.length,2);
  assert.equal((await verifyReceiptChain(bundle.receipts)).valid,true);
});
test('history restores data and receipts, isolates snapshots, and invalidates redo after a branch', async () => {
  const w=await createSeedWorkspace(); const history=new WorkspaceHistory(w,3);
  const next=addObject(w,{label:'Second',externalKey:'2'}).workspace; history.commit(next); next.name='changed outside';
  assert.equal(history.undo().objects.length,1);
  assert.equal(history.redo().name,w.name);
  history.undo(); history.commit({...w,name:'branch'}); assert.equal(history.canRedo,false);
});
test('terminal transitions cannot create duplicate judgments or completion events', async () => {
  const w=await createSeedWorkspace();
  const closed=resolveException(w,w.exceptions[0].id,{actor:'operator',decision:'checked'}).workspace;
  assert.throws(()=>resolveException(closed,w.exceptions[0].id,{actor:'operator',decision:'again'}),/already resolved/);
  const done=completeContinuation(w,w.continuations[0].id,{actor:'operator',note:'done'}).workspace;
  assert.throws(()=>completeContinuation(done,w.continuations[0].id,{actor:'operator',note:'again'}),/already completed/);
});
