#!/usr/bin/env node
/**
 * Domain Import Boundary Checker
 *
 * Validates:
 * 1. No @customer-portal/domain (root) imports
 * 2. No deep imports beyond module/providers
 * 3. Portal has zero provider imports
 */

import fs from "node:fs/promises";
import path from "node:path";

const ROOT = process.cwd();

const APPS_DIR = path.join(ROOT, "apps");
const BFF_SRC_DIR = path.join(APPS_DIR, "bff", "src");
const PORTAL_SRC_DIR = path.join(APPS_DIR, "portal", "src");

const FILE_EXTS = new Set([".ts", ".tsx", ".js", ".jsx"]);
const IGNORE_DIRS = new Set(["node_modules", "dist", ".next", ".turbo", ".cache"]);

function toPos(text, idx) {
  // 1-based line/column
  let line = 1;
  let col = 1;
  for (let i = 0; i < idx; i += 1) {
    if (text.charCodeAt(i) === 10) {
      line += 1;
      col = 1;
    } else {
      col += 1;
    }
  }
  return { line, col };
}

async function* walk(dir) {
  const entries = await fs.readdir(dir, { withFileTypes: true });
  for (const e of entries) {
    const p = path.join(dir, e.name);
    if (e.isDirectory()) {
      if (IGNORE_DIRS.has(e.name) || e.name.startsWith(".")) continue;
      yield* walk(p);
      continue;
    }
    if (!e.isFile()) continue;
    if (!FILE_EXTS.has(path.extname(e.name))) continue;
    yield p;
  }
}

function collectDomainImports(code) {
  const results = [];

  const patterns = [
    { kind: "from", re: /\bfrom\s+['"]([^'"]+)['"]/g },
    { kind: "import", re: /\bimport\s+['"]([^'"]+)['"]/g },
    { kind: "dynamicImport", re: /\bimport\(\s*['"]([^'"]+)['"]\s*\)/g },
    { kind: "require", re: /\brequire\(\s*['"]([^'"]+)['"]\s*\)/g },
  ];

  for (const { kind, re } of patterns) {
    for (const m of code.matchAll(re)) {
      const spec = m[1];
      if (!spec || !spec.startsWith("@customer-portal/domain")) continue;
      const idx = typeof m.index === "number" ? m.index : 0;
      results.push({ kind, spec, idx });
    }
  }

  return results;
}

function validateSpecifier({ spec, isPortal }) {
  if (spec === "@customer-portal/domain") {
    return "Do not import @customer-portal/domain (root). Use @customer-portal/domain/<module> instead.";
  }

  if (spec.includes("/src/")) {
    return "Import from @customer-portal/domain/<module> instead of internals.";
  }

  if (spec.startsWith("@customer-portal/domain/toolkit/")) {
    return "Do not deep-import toolkit internals. Import from @customer-portal/domain/toolkit only.";
  }

  if (/^@customer-portal\/domain\/[^/]+\/providers\/.+/.test(spec)) {
    return "Do not deep-import provider internals. Import from @customer-portal/domain/<module>/providers only.";
  }

  if (/^@customer-portal\/domain\/[^/]+\/providers$/.test(spec)) {
    if (isPortal) {
      return "Portal must not import provider adapters/types. Import normalized domain models from @customer-portal/domain/<module> instead.";
    }
    return null;
  }

  // Any 2+ segment import like @customer-portal/domain/a/b is illegal everywhere
  // (except the explicit .../<module>/providers entrypoint handled above).
  if (/^@customer-portal\/domain\/[^/]+\/[^/]+/.test(spec)) {
    return "No deep @customer-portal/domain imports. Use @customer-portal/domain/<module> (or BFF-only: .../<module>/providers).";
  }

  return null;
}

async function main() {
  const errors = [];

  // Broad scan: both apps for root/deep imports
  for (const baseDir of [BFF_SRC_DIR, PORTAL_SRC_DIR]) {
    for await (const file of walk(baseDir)) {
      const code = await fs.readFile(file, "utf8");
      const isPortal = file.startsWith(PORTAL_SRC_DIR + path.sep);

      for (const imp of collectDomainImports(code)) {
        const message = validateSpecifier({ spec: imp.spec, isPortal });
        if (!message) continue;
        const pos = toPos(code, imp.idx);
        errors.push({
          file: path.relative(ROOT, file),
          line: pos.line,
          col: pos.col,
          spec: imp.spec,
          message,
        });
      }
    }
  }

  if (errors.length > 0) {
    console.error(`[domain] ERROR: illegal domain imports detected (${errors.length})`);
    for (const e of errors) {
      console.error(`[domain] ${e.file}:${e.line}:${e.col}  ${e.spec}`);
      console.error(`         ${e.message}`);
    }
    process.exit(1);
  }

  console.log("[domain] OK: import contract checks passed.");
}

await main();
