#!/usr/bin/env node
/**
 * Lints client/messages/fa.json against the banned-orthography-variant rules in
 * docs/rules/client/i18n.md §4 — enforces the phase-12 copy sweep so it cannot silently regress.
 * Exits non-zero (and prints every offending key) on any match.
 *
 * The rules below are the machine-checkable subset. The full Persian style guide (glossary, register,
 * shell naming, the ZWNJ cases a grep can't express) lives in that doc; keep the two in step.
 */
import { readFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';

const __dirname = dirname(fileURLToPath(import.meta.url));
const FA_MESSAGES_PATH = join(__dirname, '..', 'messages', 'fa.json');

// Each rule scans the *raw value* of every leaf string in fa.json (flattened key path → value).
// `pattern` is a plain substring (not regex) so ZWNJ/hamza characters stay literal and unambiguous.
const RULES = [
  {
    name: 'brand name must use ZWNJ (بالین‌یار), never a plain space',
    pattern: 'بالین یار',
  },
  {
    name: 'تأیید must use hamza — تایید (hamza-less) is banned',
    pattern: 'تایید',
  },
  {
    name: 'جستجو is the one standard form — جست‌وجو is banned',
    pattern: 'جست‌وجو',
  },
  {
    name: 'جستجو is the one standard form — جست و جو (spaced) is banned',
    pattern: 'جست و جو',
  },
  {
    name: 'the indefinite «ی» misattachment bug — «بازی» (game) instead of «ی» on the right word',
    // Word-boundary trap: catches "... بازی " (space after) so it doesn't also flag words that
    // legitimately contain "بازی" as a substring of something else — in this catalog there are none,
    // but the trailing-space anchor keeps the check honest if one is ever added on purpose elsewhere.
    pattern: 'بازی ',
  },
  {
    // Leading space distinguishes the archaic passive auxiliary ("X می‌گردد" = "is X-ed") from the
    // unrelated, entirely legitimate verb «برمی‌گردد» (returns/comes back), which fuses «بر» directly
    // onto «می‌گردد» with no space and must never be flagged.
    name: 'archaic passive می‌گردد is banned — use می‌شود',
    pattern: ' می‌گردد',
  },
];

function flattenStrings(value, path, out) {
  if (typeof value === 'string') {
    out.push([path, value]);
    return;
  }
  if (Array.isArray(value)) {
    value.forEach((item, index) => flattenStrings(item, `${path}[${index}]`, out));
    return;
  }
  if (value && typeof value === 'object') {
    for (const [key, child] of Object.entries(value)) {
      flattenStrings(child, path ? `${path}.${key}` : key, out);
    }
  }
}

function main() {
  const raw = readFileSync(FA_MESSAGES_PATH, 'utf8');
  const messages = JSON.parse(raw);
  const leaves = [];
  flattenStrings(messages, '', leaves);

  const failures = [];
  for (const rule of RULES) {
    for (const [path, value] of leaves) {
      if (value.includes(rule.pattern)) {
        failures.push({ rule: rule.name, path, value });
      }
    }
  }

  if (failures.length === 0) {
    console.log(`check-copy: ${leaves.length} strings checked, 0 banned variants found.`);
    return;
  }

  console.error(`check-copy: found ${failures.length} banned copy variant(s):\n`);
  for (const failure of failures) {
    console.error(`  [${failure.rule}]`);
    console.error(`    fa.json → ${failure.path}: "${failure.value}"\n`);
  }
  process.exitCode = 1;
}

main();
