// ST-BME: i18n import boundary enforcement
// Ensures that prompt/data modules (prompting/**, retrieval/injector.js,
// graph/schema.js, sync/**, vector/**) do NOT import from the i18n module.
// This is a static analysis guard: i18n is UI-only and must not leak into
// data-pipeline or prompt-building code.
import assert from "node:assert/strict";
import { readFileSync, readdirSync } from "node:fs";

// ─── Configuration ───────────────────────────────────────────────────────────

const PROJECT_ROOT = new URL("..", import.meta.url).pathname;

const BOUNDARY_PATTERNS = [
  // i18n module import patterns to forbid
  /from\s+["'](?:\.\.\/)+i18n(?:\/[^"']*)?["']/,
  /require\s*\(\s*["'](?:\.\.\/)+i18n(?:\/[^"']*)?["']\s*\)/,
  /import\s*\(\s*["'](?:\.\.\/)+i18n(?:\/[^"']*)?["']\s*\)/,
];

const BOUNDARY_MODULES = [
  // prompting/ — all files in the prompting directory
  { dir: "prompting", files: null },
  // retrieval/injector.js specifically
  { dir: "retrieval", files: ["injector.js"] },
  // graph/schema.js specifically
  { dir: "graph", files: ["schema.js"] },
  // sync/ — all files in the sync directory
  { dir: "sync", files: null },
  // vector/ — all files in the vector directory
  { dir: "vector", files: null },
];

// ─── Helpers ─────────────────────────────────────────────────────────────────

function readProjectFile(relativePath) {
  return readFileSync(PROJECT_ROOT + relativePath, "utf8");
}

/**
 * Check if a source file contains any forbidden i18n import pattern.
 * Returns violations found, or an empty array.
 */
function checkI18nImports(source, filePath) {
  const violations = [];
  for (const pattern of BOUNDARY_PATTERNS) {
    const match = source.match(pattern);
    if (match) {
      const lineNum = source.substring(0, match.index).split("\n").length;
      violations.push({ filePath, line: lineNum, match: match[0].trim() });
    }
  }
  return violations;
}

/**
 * Get all .js files in a directory (non-recursive for simplicity; the
 * project's restricted dirs are flat).
 */
function getJsFilesInDir(dirPath) {
  const entries = readdirSync(PROJECT_ROOT + dirPath, { withFileTypes: true });
  return entries
    .filter((entry) => entry.isFile() && entry.name.endsWith(".js"))
    .map((entry) => entry.name);
}

// ─── Tests ───────────────────────────────────────────────────────────────────

const allViolations = [];

for (const entry of BOUNDARY_MODULES) {
  const fileList = entry.files || getJsFilesInDir(entry.dir);
  for (const filename of fileList) {
    const relativePath = `${entry.dir}/${filename}`;
    let source;
    try {
      source = readProjectFile(relativePath);
    } catch {
      console.warn(`[i18n-boundary] SKIP — file not found: ${relativePath}`);
      continue;
    }
    const violations = checkI18nImports(source, relativePath);
    allViolations.push(...violations);
  }
}

if (allViolations.length > 0) {
  const report = allViolations
    .map(
      (v) => `  ${v.filePath}:${v.line} — ${v.match}`,
    )
    .join("\n");
  assert.fail(
    `i18n import boundary violation(s) found in ${allViolations.length} location(s):\n${report}\n\n` +
      "i18n is UI-only. Prompt/data modules (prompting/**, retrieval/injector.js, " +
      "graph/schema.js, sync/**, vector/**) must not import i18n.",
  );
}

// Optional: verify that the boundary modules themselves are valid JS by
// checking for obvious syntax issues (e.g., unmatched braces, obviously
// malformed import statements that might hide i18n imports).
// This is a lightweight sanity check, not a full parse.

const MINIMAL_FILE_COUNT = {
  prompting: 9,
  retrieval: 1, // injector.js only
  graph: 1, // schema.js only
  sync: 13,
  vector: 6,
};

for (const entry of BOUNDARY_MODULES) {
  if (entry.files) {
    for (const filename of entry.files) {
      const relativePath = `${entry.dir}/${filename}`;
      try {
        const source = readProjectFile(relativePath);
        // Ensure the file has at least some content
        assert.ok(
          source.trim().length > 0,
          `${relativePath} is empty — cannot verify boundary compliance`,
        );
      } catch {
        // Already warned above — skip
      }
    }
  } else {
    const dirFiles = getJsFilesInDir(entry.dir);
    assert.ok(
      dirFiles.length >= (MINIMAL_FILE_COUNT[entry.dir] || 1),
      `${entry.dir} expected at least ${MINIMAL_FILE_COUNT[entry.dir]} .js files for boundary coverage, got ${dirFiles.length}`,
    );
  }
}

console.log("i18n boundary enforcement tests passed");
console.log(`  Scanned modules: ${BOUNDARY_MODULES.length} directories / files`);
console.log(`  Violations found: ${allViolations.length}`);
