import { test } from 'node:test';
import assert from 'node:assert/strict';
import { readFile } from 'node:fs/promises';
import { fileURLToPath } from 'node:url';
import { dirname, resolve } from 'node:path';

const __dirname = dirname(fileURLToPath(import.meta.url));
const DATA_PATH = resolve(__dirname, '..', 'lint-forbidden-words.json');

async function loadData() {
  const raw = await readFile(DATA_PATH, 'utf8');
  return JSON.parse(raw);
}

test('forbidden-words JSON parses successfully', async () => {
  const data = await loadData();
  assert.equal(typeof data, 'object');
  assert.ok(data !== null);
});

test('top-level keys present (tier1, tier2, tier3)', async () => {
  const data = await loadData();
  assert.ok(Array.isArray(data.tier1), 'tier1 must be an array');
  assert.ok(Array.isArray(data.tier2), 'tier2 must be an array');
  assert.ok(Array.isArray(data.tier3), 'tier3 must be an array');
});

test('tier1 has 19 entries (verbatim from research/03 SC-3 list line 200)', async () => {
  const data = await loadData();
  assert.equal(data.tier1.length, 19, `expected 19 tier1 entries, got ${data.tier1.length}`);
});

test('tier2 has 24 entries (verbatim from research/03 SC-3 list line 201)', async () => {
  const data = await loadData();
  assert.equal(data.tier2.length, 24, `expected 24 tier2 entries, got ${data.tier2.length}`);
});

test('tier3 has 12 entries (verbatim from research/03 SC-3 list line 202 + hook)', async () => {
  const data = await loadData();
  assert.equal(data.tier3.length, 12, `expected 12 tier3 entries, got ${data.tier3.length}`);
});

test('every entry has required fields (word, replacement, source, tier)', async () => {
  const data = await loadData();
  for (const tierName of ['tier1', 'tier2', 'tier3']) {
    for (const entry of data[tierName]) {
      assert.ok(typeof entry.word === 'string' && entry.word.length > 0,
        `${tierName} entry missing 'word': ${JSON.stringify(entry)}`);
      assert.ok(typeof entry.replacement === 'string' && entry.replacement.length > 0,
        `${tierName} entry "${entry.word}" missing 'replacement'`);
      assert.ok(typeof entry.source === 'string' && entry.source.length > 0,
        `${tierName} entry "${entry.word}" missing 'source'`);
      assert.ok(entry.tier === Number(tierName.replace('tier', '')),
        `${tierName} entry "${entry.word}" has wrong tier: ${entry.tier}`);
    }
  }
});

test('tier1 spot-check — required absolute prohibitions present', async () => {
  const data = await loadData();
  const words = data.tier1.map((e) => e.word);
  for (const required of ['utilize', 'leverage', 'facilitate', 'terminate', 'abort', 'invalid', 'illegal', 'failed to', 'fatal', 'in order to']) {
    assert.ok(words.includes(required), `tier1 missing required word: ${required}`);
  }
});

test('tier2 spot-check — condescending words present', async () => {
  const data = await loadData();
  const words = data.tier2.map((e) => e.word);
  for (const required of ['simply', 'just', 'obviously', 'clearly']) {
    assert.ok(words.includes(required), `tier2 missing required word: ${required}`);
  }
});

test('tier3 spot-check — domain-specific jargon present', async () => {
  const data = await loadData();
  const words = data.tier3.map((e) => e.word);
  for (const required of ['CLAUDE.md', '@import', 'MCP', 'hook', 'frontmatter']) {
    assert.ok(words.includes(required), `tier3 missing required word: ${required}`);
  }
});

test('no duplicate words across tiers', async () => {
  const data = await loadData();
  const allWords = [
    ...data.tier1.map((e) => e.word),
    ...data.tier2.map((e) => e.word),
    ...data.tier3.map((e) => e.word),
  ];
  const seen = new Set();
  const dupes = [];
  for (const w of allWords) {
    if (seen.has(w)) dupes.push(w);
    seen.add(w);
  }
  assert.equal(dupes.length, 0, `duplicate forbidden words across tiers: ${dupes.join(', ')}`);
});
