import { readFileSync, writeFileSync, mkdirSync, readdirSync, statSync } from "node:fs";
import { join, dirname, relative } from "node:path";

const PLACEHOLDER_RE = /\{\{([A-Z0-9_]+)\}\}/g;

/**
 * Replace all {{VARIABLE_NAME}} placeholders in a string with values from the
 * variables object. Warns to stderr for any placeholder that has no value.
 */
function substitute(content, variables, sourcePath) {
  return content.replace(PLACEHOLDER_RE, (match, key) => {
    if (Object.prototype.hasOwnProperty.call(variables, key)) {
      return variables[key];
    }
    process.stderr.write(
      `[templates] Warning: no value for placeholder {{${key}}} in ${sourcePath}\n`
    );
    return match;
  });
}

/**
 * Read templatePath, replace {{VARIABLE_NAME}} placeholders with values from
 * variables, then write the result to outputPath (creating directories as needed).
 */
export function processTemplate(templatePath, outputPath, variables) {
  const raw = readFileSync(templatePath, "utf-8");
  const processed = substitute(raw, variables, templatePath);
  mkdirSync(dirname(outputPath), { recursive: true });
  writeFileSync(outputPath, processed, "utf-8");
}

/**
 * Recursively process all files in srcDir, substituting placeholders with
 * values from variables, and write outputs to the corresponding paths under
 * destDir. Directories are created as needed.
 */
export function processDirectory(srcDir, destDir, variables) {
  const entries = readdirSync(srcDir);
  for (const entry of entries) {
    const srcPath = join(srcDir, entry);
    const destPath = join(destDir, entry);
    const stat = statSync(srcPath);
    if (stat.isDirectory()) {
      processDirectory(srcPath, destPath, variables);
    } else {
      processTemplate(srcPath, destPath, variables);
    }
  }
}
