/**
 * Sanity check：orderLogsByHashChain 按 previousHash 拓扑排序
 *
 * 回归 ERR-20260509-001：audit_log.when 是 timestamptz(3)，verifyIntegrity
 * 单 orderBy when 在同 ms ties 上不稳定 → previousHash 链伪断 → verified=false。
 * 修法：按 previousHash → currentHash 拓扑遍历重排，与时间精度无关。
 *
 * 跑法：
 *   cd backend
 *   npx ts-node --transpile-only scripts/probes/audit-order-logs-by-hash-chain.ts
 *
 * 不替代 spec（jest infra 当前损坏）；纯逻辑 sanity，喂打乱顺序的数组检查输出。
 */
import { orderLogsByHashChain } from '../../src/core/observability/audit/utils/order-logs-by-hash-chain';

type Log = { id: string; previousHash: string | null; currentHash: string };

function chain(n: number): Log[] {
  const logs: Log[] = [];
  let prev: string | null = null;
  for (let i = 0; i < n; i++) {
    const curr = `h${i}`;
    logs.push({ id: `log-${i}`, previousHash: i === 0 ? null : prev, currentHash: curr });
    prev = curr;
  }
  return logs;
}

function shuffle<T>(arr: T[]): T[] {
  const a = [...arr];
  for (let i = a.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [a[i], a[j]] = [a[j], a[i]];
  }
  return a;
}

function ids(logs: Log[]): string[] {
  return logs.map((l) => l.id);
}

interface Case {
  name: string;
  input: Log[];
  expect: string[];
}

function reverseInput(): Log[] {
  return [...chain(5)].reverse();
}

const cases: Case[] = [
  {
    name: '已按链序：原样返回',
    input: chain(5),
    expect: ['log-0', 'log-1', 'log-2', 'log-3', 'log-4'],
  },
  {
    name: '完全倒序：拓扑还原写入序',
    input: reverseInput(),
    expect: ['log-0', 'log-1', 'log-2', 'log-3', 'log-4'],
  },
  {
    name: '空数组：原样返回',
    input: [],
    expect: [],
  },
  {
    name: '单元素：原样返回',
    input: [{ id: 'solo', previousHash: null, currentHash: 'h0' }],
    expect: ['solo'],
  },
  {
    name: 'GENESIS 字面量起点（previousHash="GENESIS"）',
    input: [
      { id: 'b', previousHash: 'h0', currentHash: 'h1' },
      { id: 'a', previousHash: 'GENESIS', currentHash: 'h0' },
      { id: 'c', previousHash: 'h1', currentHash: 'h2' },
    ],
    expect: ['a', 'b', 'c'],
  },
  {
    name: '链断：起点+链头追加在前，孤立尾节点追加到后',
    input: [
      { id: 'orphan', previousHash: 'h99', currentHash: 'h100' },
      { id: 'b', previousHash: 'h0', currentHash: 'h1' },
      { id: 'a', previousHash: null, currentHash: 'h0' },
    ],
    expect: ['a', 'b', 'orphan'],
  },
  {
    name: '无起点（无 GENESIS / null）：fallback 到原输入序',
    input: [
      { id: 'x', previousHash: 'hX', currentHash: 'h1' },
      { id: 'y', previousHash: 'h1', currentHash: 'h2' },
    ],
    expect: ['x', 'y'],
  },
];

// 随机打乱场景：连续 100 次随机打乱 8 条链，必须每次都能还原写入序
function randomShuffleCase(): { ok: boolean; failedAt?: number } {
  const original = chain(8);
  for (let i = 0; i < 100; i++) {
    const shuffled = shuffle(original);
    const out = ids(orderLogsByHashChain(shuffled));
    const expected = ids(original);
    if (JSON.stringify(out) !== JSON.stringify(expected)) {
      return { ok: false, failedAt: i };
    }
  }
  return { ok: true };
}

let pass = 0;
let fail = 0;
for (const c of cases) {
  const out = ids(orderLogsByHashChain(c.input));
  const ok = JSON.stringify(out) === JSON.stringify(c.expect);
  if (ok) {
    pass++;
    console.log(`✅ ${c.name}`);
  } else {
    fail++;
    console.log(`❌ ${c.name}`);
    console.log(`   expected: ${JSON.stringify(c.expect)}`);
    console.log(`   got:      ${JSON.stringify(out)}`);
  }
}

const r = randomShuffleCase();
if (r.ok) {
  pass++;
  console.log('✅ 随机打乱 100 次 × 8 条链：每次都还原写入序');
} else {
  fail++;
  console.log(`❌ 随机打乱第 ${r.failedAt} 次未还原写入序`);
}

console.log(`\n${pass} pass / ${fail} fail`);
process.exit(fail > 0 ? 1 : 0);
