import fs from "node:fs";
import path from "node:path";
import { PACKAGE_ROOT, readErpKitVersion } from "../util";

// Files that need renaming because they cause issues in the repo/pack.
// npm renames .gitignore during pack (npm/cli#5756).
// pnpm-workspace.yaml causes the template dir to be treated as a workspace member.
// prepack copies these to their safe names; scaffold time restores the originals.
const RENAME_MAP: Record<string, string> = {
  __dot__gitignore: ".gitignore",
  "__pnpm-workspace.yaml": "pnpm-workspace.yaml",
};

export function copyTemplateDir(
  srcDir: string,
  destDir: string,
  replacements: Record<string, string>,
  placeholderFiles: Set<string>,
): void {
  for (const entry of fs.readdirSync(srcDir, { withFileTypes: true })) {
    const srcPath = path.join(srcDir, entry.name);
    const destName = RENAME_MAP[entry.name] ?? entry.name;
    const destPath = path.join(destDir, destName);

    // Only needed for local dev — published packages won't contain node_modules.
    if (entry.name === "node_modules") continue;

    if (entry.isDirectory()) {
      fs.mkdirSync(destPath, { recursive: true });
      copyTemplateDir(srcPath, destPath, replacements, placeholderFiles);
    } else {
      if (fs.existsSync(destPath)) continue;
      if (placeholderFiles.has(entry.name)) {
        let content = fs.readFileSync(srcPath, "utf-8");
        for (const [from, to] of Object.entries(replacements)) {
          content = content.replaceAll(from, to);
        }
        fs.writeFileSync(destPath, content);
      } else {
        fs.copyFileSync(srcPath, destPath);
      }
    }
  }
}

export function scaffoldModuleBoilerplate(moduleDir: string, moduleName: string): void {
  const templateDir = path.join(PACKAGE_ROOT, "templates", "scaffold", "module");
  const erpKitVersion = readErpKitVersion();
  const replacements = {
    "template-module": moduleName,
    '"workspace:*"': `"${erpKitVersion}"`,
  };
  const placeholderFiles = new Set(["package.json", "tailor.config.ts"]);
  copyTemplateDir(templateDir, moduleDir, replacements, placeholderFiles);
}

export function listAppTemplates(): string[] {
  const appTemplateRoot = path.join(PACKAGE_ROOT, "templates", "scaffold", "app");
  return fs
    .readdirSync(appTemplateRoot, { withFileTypes: true })
    .filter((e) => e.isDirectory())
    .map((e) => e.name);
}

export function scaffoldAppBoilerplate(
  appDir: string,
  appName: string,
  templateName: string,
): void {
  const templateDir = path.join(PACKAGE_ROOT, "templates", "scaffold", "app", templateName);
  const erpKitVersion = readErpKitVersion();
  const replacements = {
    "template-app-frontend": `${appName}-frontend`,
    "template-app-backend": appName,
    "template-app": appName,
    '"workspace:*"': `"${erpKitVersion}"`,
  };
  const placeholderFiles = new Set(["package.json", "tailor.config.ts", "index.html", "setup.ts"]);
  copyTemplateDir(templateDir, appDir, replacements, placeholderFiles);
}

export function scaffoldProjectBoilerplate(projectDir: string, projectName: string): void {
  const templateDir = path.join(PACKAGE_ROOT, "templates", "scaffold", "project");
  const erpKitVersion = readErpKitVersion();
  const replacements = {
    "template-project": projectName,
    '"workspace:*"': `"${erpKitVersion}"`,
  };
  const placeholderFiles = new Set(["package.json"]);
  copyTemplateDir(templateDir, projectDir, replacements, placeholderFiles);
}
