/**
 * Sanity check：LogWriterService.dropOverflow 优先级丢弃 + ERROR/WARN 兜底落文件
 *
 * 跑法：
 *   cd backend
 *   npx ts-node --transpile-only scripts/probes/log-writer-overflow.ts
 *
 * 不替代 spec 文件（jest infra 修好后启用 spec 跑 CI）；当前跑这个看规则是否符合预期。
 */
import { LogWriterService, LogEntry } from '../../src/core/observability/logging/services/log-writer.service';

type Level = LogEntry['level'];

function entry(level: Level, idx: number): LogEntry {
  return {
    traceId: `t-${idx}`,
    requestId: `r-${idx}`,
    level,
    message: `${level}#${idx}`,
  };
}

function seed(writer: LogWriterService, levels: Level[]): void {
  const buf: LogEntry[] = (writer as any).buffer;
  buf.length = 0;
  levels.forEach((lv, i) => buf.push(entry(lv, i)));
}

function setupWriter(): { writer: LogWriterService; fileWrites: LogEntry[] } {
  const stubPrisma: any = { systemLog: { createMany: async () => {}, create: async () => {} } };
  const writer = new LogWriterService(stubPrisma);
  const fileWrites: LogEntry[] = [];
  // 拦截 writeToFile，捕获兜底写入
  (writer as any).writeToFile = (e: LogEntry) => fileWrites.push(e);
  return { writer, fileWrites };
}

function countBy(buf: LogEntry[]): Record<Level, number> {
  const c: Record<Level, number> = { ERROR: 0, WARN: 0, INFO: 0, DEBUG: 0 };
  for (const e of buf) c[e.level]++;
  return c;
}

interface Case {
  name: string;
  seedLevels: Level[];
  expectSurvive: Partial<Record<Level, number>>;
  expectFileWritesByLevel: Partial<Record<Level, number>>;
}

const MAX = 1000;

const cases: Case[] = [
  {
    name: '混合溢出 1000DEBUG+500INFO+250WARN+250ERROR (2000) → 丢全部 DEBUG，INFO/WARN/ERROR 全留',
    seedLevels: [
      ...Array(1000).fill('DEBUG' as Level),
      ...Array(500).fill('INFO' as Level),
      ...Array(250).fill('WARN' as Level),
      ...Array(250).fill('ERROR' as Level),
    ],
    expectSurvive: { DEBUG: 0, INFO: 500, WARN: 250, ERROR: 250 },
    expectFileWritesByLevel: { DEBUG: 0, INFO: 0, WARN: 0, ERROR: 0 },
  },
  {
    name: '级联丢：500DEBUG+1500INFO+100WARN+100ERROR (2200) → 丢全部 DEBUG + 700 INFO',
    seedLevels: [
      ...Array(500).fill('DEBUG' as Level),
      ...Array(1500).fill('INFO' as Level),
      ...Array(100).fill('WARN' as Level),
      ...Array(100).fill('ERROR' as Level),
    ],
    expectSurvive: { DEBUG: 0, INFO: 800, WARN: 100, ERROR: 100 },
    expectFileWritesByLevel: {},
  },
  {
    name: '微溢出 990DEBUG + 5INFO + 5WARN + 5ERROR (1005) → 丢 5 DEBUG',
    seedLevels: [
      ...Array(990).fill('DEBUG' as Level),
      ...Array(5).fill('INFO' as Level),
      ...Array(5).fill('WARN' as Level),
      ...Array(5).fill('ERROR' as Level),
    ],
    expectSurvive: { DEBUG: 985, INFO: 5, WARN: 5, ERROR: 5 },
    expectFileWritesByLevel: { DEBUG: 0, INFO: 0, WARN: 0, ERROR: 0 },
  },
  {
    name: '极端：1010 全 ERROR → 丢 10 ERROR 且全部落文件兜底',
    seedLevels: Array(1010).fill('ERROR' as Level),
    expectSurvive: { ERROR: 1000 },
    expectFileWritesByLevel: { ERROR: 10 },
  },
  {
    name: 'WARN 兜底：900DEBUG + 110WARN (1010) → 丢 10 DEBUG，无兜底落文件',
    seedLevels: [
      ...Array(900).fill('DEBUG' as Level),
      ...Array(110).fill('WARN' as Level),
    ],
    expectSurvive: { DEBUG: 890, WARN: 110 },
    expectFileWritesByLevel: { WARN: 0 },
  },
  {
    name: 'WARN 兜底：1010WARN → 丢 10 WARN 且全部落文件',
    seedLevels: Array(1010).fill('WARN' as Level),
    expectSurvive: { WARN: 1000 },
    expectFileWritesByLevel: { WARN: 10 },
  },
  {
    name: '无溢出：500 DEBUG → 不丢',
    seedLevels: Array(500).fill('DEBUG' as Level),
    expectSurvive: { DEBUG: 500 },
    expectFileWritesByLevel: {},
  },
];

let pass = 0;
let fail = 0;

for (const c of cases) {
  const { writer, fileWrites } = setupWriter();
  seed(writer, c.seedLevels);
  (writer as any).dropOverflow();

  const buf: LogEntry[] = (writer as any).buffer;
  const surviveCounts = countBy(buf);
  const fileCounts = countBy(fileWrites);

  const surviveOk = (Object.keys(c.expectSurvive) as Level[]).every(
    (lv) => surviveCounts[lv] === c.expectSurvive[lv],
  );
  const fileOk = (['ERROR', 'WARN', 'INFO', 'DEBUG'] as Level[]).every(
    (lv) => (c.expectFileWritesByLevel[lv] ?? 0) === fileCounts[lv],
  );
  const totalOk = c.seedLevels.length <= MAX
    ? buf.length === c.seedLevels.length
    : buf.length === MAX;

  const ok = surviveOk && fileOk && totalOk;
  if (ok) {
    console.log(`✅ ${c.name}`);
    pass++;
  } else {
    console.log(`❌ ${c.name}`);
    console.log(`   survive expected: ${JSON.stringify(c.expectSurvive)}`);
    console.log(`   survive actual  : ${JSON.stringify(surviveCounts)}`);
    console.log(`   file expected   : ${JSON.stringify(c.expectFileWritesByLevel)}`);
    console.log(`   file actual     : ${JSON.stringify(fileCounts)}`);
    console.log(`   buffer total    : ${buf.length}`);
    fail++;
  }
}

console.log(`\nResult: ${pass}/${cases.length} passed, ${fail} failed`);
process.exit(fail > 0 ? 1 : 0);
