/**
 * lib/template-loader.ts — Handlebars template loader for dev CLIs.
 *
 * Loads a .hbs file from a directory, registers a small set of helpers used by
 * SmartStack scaffolders (case conversions, join, eq), and returns a render function.
 *
 * Usage:
 *   import { loadTemplate } from '../../../../lib/template-loader.js';
 *   const render = await loadTemplate('entity.cs.hbs', import.meta.url);
 *   const rendered = render({ name: 'Employee', module: 'HR' });
 */
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import Handlebars from 'handlebars';
import { readText } from './fs.js';
import {
  toKebabCase,
  toCamelCase,
  toPascalCase,
  capitalize,
  singularize,
  pluralize,
} from './string-utils.js';

// ─── Shared helper registration (runs once per process) ───────────────────

let helpersRegistered = false;

function registerHelpers(): void {
  if (helpersRegistered) return;

  Handlebars.registerHelper('kebab', (s: unknown) => toKebabCase(String(s ?? '')));
  Handlebars.registerHelper('camel', (s: unknown) => toCamelCase(String(s ?? '')));
  Handlebars.registerHelper('pascal', (s: unknown) => toPascalCase(String(s ?? '')));
  Handlebars.registerHelper('capitalize', (s: unknown) => capitalize(String(s ?? '')));
  Handlebars.registerHelper('singular', (s: unknown) => singularize(String(s ?? '')));
  Handlebars.registerHelper('plural', (s: unknown) => pluralize(String(s ?? '')));

  Handlebars.registerHelper('eq', (a: unknown, b: unknown) => a === b);
  Handlebars.registerHelper('neq', (a: unknown, b: unknown) => a !== b);

  Handlebars.registerHelper('join', (arr: unknown, sep: unknown) => {
    if (!Array.isArray(arr)) return '';
    return arr.join(String(sep ?? ', '));
  });

  Handlebars.registerHelper('includes', (arr: unknown, value: unknown) => {
    if (!Array.isArray(arr)) return false;
    return arr.includes(value);
  });

  helpersRegistered = true;
}

// ─── Public API ────────────────────────────────────────────────────────────

/**
 * Load a Handlebars template by name from a directory.
 *
 * @param templateFile - The .hbs filename (e.g. "entity.cs.hbs")
 * @param dirHint      - Either a directory path, a file path, or an import.meta.url.
 *                       If the hint is a URL or a file path, the loader resolves
 *                       the containing directory and looks for `templates/<name>`
 *                       inside it.
 * @returns A function that takes a data object and returns the rendered string.
 */
export async function loadTemplate(
  templateFile: string,
  dirHint: string,
): Promise<(data: Record<string, unknown>) => string> {
  registerHelpers();

  const baseDir = resolveTemplatesDir(dirHint);
  const templatePath = path.join(baseDir, templateFile);
  const source = await readText(templatePath);
  return Handlebars.compile(source, { noEscape: true });
}

/**
 * Synchronous variant — load and compile several templates at once.
 * Returns a map { templateFile → render function }.
 */
export async function loadTemplates(
  templateFiles: string[],
  dirHint: string,
): Promise<Map<string, (data: Record<string, unknown>) => string>> {
  const map = new Map<string, (data: Record<string, unknown>) => string>();
  for (const file of templateFiles) {
    map.set(file, await loadTemplate(file, dirHint));
  }
  return map;
}

// ─── Internals ─────────────────────────────────────────────────────────────

function resolveTemplatesDir(hint: string): string {
  // import.meta.url → file:// URL
  if (hint.startsWith('file:')) {
    const dir = path.dirname(fileURLToPath(hint));
    return path.join(dir, 'templates');
  }

  // Absolute path
  if (path.isAbsolute(hint)) {
    // If hint ends with .ts/.js assume it's a file → use its parent dir
    if (hint.endsWith('.ts') || hint.endsWith('.js') || hint.endsWith('.mjs')) {
      return path.join(path.dirname(hint), 'templates');
    }
    // Otherwise assume it's a directory → append templates/
    return path.join(hint, 'templates');
  }

  // Relative path → resolve from cwd
  return path.resolve(process.cwd(), hint, 'templates');
}
