#!/usr/bin/env node
/**
 * TorbatYar frontend architecture validator (Phase 1).
 * Checks directory scaffold and cross-module import boundaries.
 * Does not modify source files.
 */
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
import { join, relative, sep } from "node:path";
import { fileURLToPath } from "node:url";

const ROOT = join(fileURLToPath(new URL(".", import.meta.url)), "..");

const REQUIRED_DIRS = [
  "modules",
  "shared",
  "shared/ui",
  "shared/forms",
  "shared/layouts",
  "shared/tables",
  "shared/charts",
  "shared/calendar",
  "shared/hooks",
  "shared/utils",
  "shared/api",
  "shared/theme",
  "shared/providers",
  "shared/icons",
  "shared/types",
  "shared/constants",
  "shared/design-system",
  "docs",
];

const SOURCE_DIRS = ["app", "components", "hooks", "lib", "modules", "src"];
const SOURCE_EXT = new Set([".ts", ".tsx"]);
const SKIP_DIRS = new Set(["node_modules", ".next", "docs"]);

/** @type {Record<string, string>} */
const DOMAIN_PATH_MARKERS = {
  accounting: "src/modules/accounting",
  beauty: "modules/beauty",
  healthcare: "src/modules/healthcare",
  hospitality: "modules/hospitality",
  delivery: "modules/delivery",
  admin: "components/admin",
};

/** Cross-domain import rules: file path prefix -> forbidden import substrings */
const CROSS_DOMAIN_RULES = [
  {
    name: "accounting → other domains",
    fileTest: (rel) =>
      rel.startsWith("app/accounting/") || rel.startsWith("src/modules/accounting/"),
    forbidden: [
      "@/components/beauty/",
      "@/components/healthcare/",
      "@/modules/beauty/",
      "@/src/modules/healthcare/",
      "@/src/modules/beauty/",
    ],
  },
  {
    name: "beauty → other domains",
    fileTest: (rel) =>
      rel.startsWith("app/beauty/") || rel.startsWith("modules/beauty/"),
    forbidden: [
      "@/components/accounting/",
      "@/components/healthcare/",
      "@/modules/accounting/",
      "@/src/modules/healthcare/",
    ],
  },
  {
    name: "healthcare → other domains",
    fileTest: (rel) =>
      rel.startsWith("app/healthcare/") || rel.startsWith("src/modules/healthcare/"),
    forbidden: [
      "@/components/accounting/",
      "@/components/beauty/",
      "@/modules/beauty/",
      "@/modules/accounting/",
      "@/modules/hospitality/",
      "@/src/modules/beauty/",
    ],
  },
  {
    name: "hospitality → other domains",
    fileTest: (rel) =>
      rel.startsWith("app/hospitality/") || rel.startsWith("modules/hospitality/"),
    forbidden: [
      "@/components/accounting/",
      "@/components/beauty/",
      "@/components/healthcare/",
      "@/modules/beauty/",
      "@/modules/accounting/",
      "@/modules/delivery/",
      "@/src/modules/healthcare/",
    ],
  },
  {
    name: "delivery → other domains",
    fileTest: (rel) =>
      rel.startsWith("app/delivery/") || rel.startsWith("modules/delivery/"),
    forbidden: [
      "@/components/accounting/",
      "@/components/beauty/",
      "@/components/healthcare/",
      "@/modules/beauty/",
      "@/modules/accounting/",
      "@/modules/hospitality/",
      "@/src/modules/healthcare/",
      "@/src/modules/accounting/",
    ],
  },
  {
    name: "design system → domains",
    fileTest: (rel) => rel.startsWith("components/ds/"),
    forbidden: [
      "@/components/accounting/",
      "@/components/beauty/",
      "@/components/healthcare/",
      "@/modules/beauty/",
      "@/modules/hospitality/",
      "@/src/modules/healthcare/",
      "@/src/modules/accounting/",
      "@/modules/accounting/",
    ],
  },
  {
    name: "shared → domain modules",
    fileTest: (rel) => rel.startsWith("shared/") || rel.startsWith("src/shared/"),
    forbidden: [
      "@/components/accounting/",
      "@/components/beauty/",
      "@/components/healthcare/",
      "@/modules/beauty/",
      "@/modules/hospitality/",
      "@/src/modules/healthcare/",
      "@/src/modules/accounting/",
      "@/modules/accounting/",
    ],
  },
];

const importRegex = /from\s+["']([^"']+)["']/g;

/** @param {string} dir */
function walkSourceFiles(dir, files = []) {
  if (!existsSync(dir)) return files;
  for (const entry of readdirSync(dir)) {
    if (SKIP_DIRS.has(entry)) continue;
    const full = join(dir, entry);
    const st = statSync(full);
    if (st.isDirectory()) {
      walkSourceFiles(full, files);
    } else if (SOURCE_EXT.has(entry.slice(entry.lastIndexOf(".")))) {
      files.push(full);
    }
  }
  return files;
}

function checkDirectories() {
  /** @type {string[]} */
  const missing = [];
  for (const dir of REQUIRED_DIRS) {
    const full = join(ROOT, dir);
    if (!existsSync(full)) missing.push(dir);
    else if (!existsSync(join(full, "README.md")) && dir !== "docs") {
      missing.push(`${dir}/README.md`);
    }
  }
  return missing;
}

function checkCrossDomainImports() {
  /** @type {Array<{file: string, rule: string, importPath: string}>} */
  const violations = [];

  for (const srcDir of SOURCE_DIRS) {
    const abs = join(ROOT, srcDir);
    for (const file of walkSourceFiles(abs)) {
      const rel = relative(ROOT, file).split(sep).join("/");
      const content = readFileSync(file, "utf8");
      let match;
      importRegex.lastIndex = 0;
      while ((match = importRegex.exec(content)) !== null) {
        const importPath = match[1];
        for (const rule of CROSS_DOMAIN_RULES) {
          if (!rule.fileTest(rel)) continue;
          for (const forbidden of rule.forbidden) {
            if (importPath.startsWith(forbidden)) {
              violations.push({ file: rel, rule: rule.name, importPath });
            }
          }
        }
      }
    }
  }

  // Also scan shared/ when it contains source files
  const sharedAbs = join(ROOT, "shared");
  for (const file of walkSourceFiles(sharedAbs)) {
    const rel = relative(ROOT, file).split(sep).join("/");
    const content = readFileSync(file, "utf8");
    let match;
    importRegex.lastIndex = 0;
    while ((match = importRegex.exec(content)) !== null) {
      const importPath = match[1];
      for (const rule of CROSS_DOMAIN_RULES) {
        if (!rule.fileTest(rel)) continue;
        for (const forbidden of rule.forbidden) {
          if (importPath.startsWith(forbidden)) {
            violations.push({ file: rel, rule: rule.name, importPath });
          }
        }
      }
    }
  }

  return violations;
}

function checkModulesScaffold() {
  /** @type {string[]} */
  const issues = [];
  const modulesReadme = join(ROOT, "modules", "README.md");
  if (!existsSync(modulesReadme)) {
    issues.push("modules/README.md missing");
  }
  const beautyModule = join(ROOT, "modules", "beauty");
  const healthcareModule = join(ROOT, "modules", "healthcare");
  const healthcareSrc = join(ROOT, "src", "modules", "healthcare");
  const accountingModule = join(ROOT, "src", "modules", "accounting");
  if (!existsSync(beautyModule)) issues.push("modules/beauty/ missing");
  if (!existsSync(healthcareSrc)) issues.push("src/modules/healthcare/ missing");
  if (!existsSync(accountingModule)) issues.push("src/modules/accounting/ missing");
  if (existsSync(healthcareModule) && !existsSync(healthcareSrc)) {
    issues.push("legacy modules/healthcare/ should not exist — use src/modules/healthcare/");
  }
  return issues;
}

function main() {
  console.log("TorbatYar Frontend — Architecture Validation (Phase 1)\n");

  let failed = false;

  const missing = checkDirectories();
  if (missing.length) {
    failed = true;
    console.error("❌ Missing required paths:");
    for (const m of missing) console.error(`   - ${m}`);
  } else {
    console.log("✅ Directory scaffold complete (modules/, shared/*, docs/)");
  }

  const moduleIssues = checkModulesScaffold();
  if (moduleIssues.length) {
    failed = true;
    console.error("\n❌ modules/ scaffold issues:");
    for (const i of moduleIssues) console.error(`   - ${i}`);
  } else {
    console.log("✅ modules/beauty, src/modules/healthcare, src/modules/accounting migrated");
  }

  const violations = checkCrossDomainImports();
  if (violations.length) {
    failed = true;
    console.error(`\n❌ Cross-domain import violations (${violations.length}):`);
    for (const v of violations.slice(0, 20)) {
      console.error(`   - ${v.file}: ${v.importPath} (${v.rule})`);
    }
    if (violations.length > 20) {
      console.error(`   … and ${violations.length - 20} more`);
    }
  } else {
    console.log("✅ No cross-domain import violations detected");
  }

  console.log("\n--- Summary ---");
  console.log(`Root: ${ROOT}`);
  console.log(`Required directories: ${REQUIRED_DIRS.length}`);
  console.log(`Domain markers: ${Object.keys(DOMAIN_PATH_MARKERS).join(", ")}`);

  if (failed) {
    console.error("\nArchitecture validation FAILED");
    process.exit(1);
  }

  console.log("\nArchitecture validation PASSED");
  process.exit(0);
}

main();
