/**
 * Eta template engine. Uses `<% %>` delimiters to avoid Angular `{{ }}` conflicts.
 * Helpers are injected into template data under namespaced keys (filters, mappers,
 * predicates, fmt, gen, ...) rather than as global Eta helpers.
 */
import { Eta } from 'eta';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { v4 as uuidv4, v5 as uuidv5 } from 'uuid';
import * as config from '../domain/config.js';
import * as crossSchema from '../domain/cross-schema-resolver.js';
import * as filters from '../domain/property-filters.js';
import * as mappers from '../domain/property-mappers.js';
import * as pickModel from '../domain/property-pick-model.js';
import * as predicates from '../domain/property-predicates.js';
import * as validators from '../domain/property-validators.js';
import * as width from '../domain/property-width.js';
import * as additionalApi from '../utils/additional-api.js';
import * as gen from '../utils/code-gen.js';
import * as mock from '../utils/mocker.js';
import * as fmt from '../utils/string-utils.js';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const TEMPLATES_DIR = path.resolve(__dirname, '..', '..', 'templates', 'codegen');
const eta = new Eta({
    autoEscape: false, // generating code, not HTML
    autoTrim: false, // preserve exact whitespace
    views: TEMPLATES_DIR,
});
/** Build the `gen` namespace with context-aware closures (former Handlebars helpers with implicit context). */
function buildGen(data) {
    const schema = data.schema;
    const properties = (schema?.aggregateProperties ??
        []);
    return {
        ...gen,
        i18n: () => (data.isI18n ? 'I18n' : ''),
        manyToManyArrayItems() {
            const m2m = filters.getManyToManyRelationshipProperties(properties);
            if (m2m.length === 0)
                return '';
            return m2m.map((p) => `, '${fmt.toCamelCase(p.name)}'`).join('');
        },
    };
}
const UUID_V5_NAMESPACE = '00000000-0000-0000-0000-000000000000';
/**
 * UUID helper for templates.
 * - `it.uuid()` → random v4
 * - `it.uuid(bc, mod, label)` → deterministic v5 (seeded by namespace + joined args)
 */
function uuid(...args) {
    if (args.length === 0)
        return uuidv4();
    return uuidv5(args.join('-'), UUID_V5_NAMESPACE);
}
function buildTemplateContext(data) {
    return {
        ...data,
        additionalApi,
        config,
        filters,
        fmt,
        gen: buildGen(data),
        mappers,
        mock,
        pickModel,
        predicates,
        crossSchema,
        uuid,
        validators,
        width,
    };
}
/**
 * Render an `.eta` template file found under the codegen templates directory
 * with injected utility namespaces. Returns the rendered source as a string.
 *
 * @param templatePath - Absolute or templates-dir-relative path to the `.eta`
 *   file. Absolute paths under the codegen templates dir are accepted and
 *   stripped to the relative form Eta expects.
 * @param data - Values passed to the template. They appear as `it.<key>`
 *   inside the template, together with the injected helper namespaces.
 * @throws {TypeError} If the template renders to a non-string value (e.g. an
 *   Eta compile error swallowed by an async helper).
 *
 * @example Inside a template:
 * ```eta
 * <%~ it.gen.importManager({ imports }) %>
 * <% it.filters.getEnumProperties(it.schema.aggregateProperties).forEach((p) => { -%>
 *   export const <%= it.fmt.pascal(p.name) %> = '<%= p.name %>';
 * <% }) -%>
 * ```
 */
export function render(templatePath, data) {
    // Eta prepends `views`, so convert absolute paths to relative
    const relativePath = templatePath.startsWith(TEMPLATES_DIR)
        ? templatePath.slice(TEMPLATES_DIR.length)
        : templatePath;
    const result = eta.render(relativePath, buildTemplateContext(data));
    if (typeof result !== 'string') {
        throw new TypeError(`Template render returned non-string for ${templatePath}`);
    }
    return result;
}
/**
 * Render a raw template string (not a file) with the same helper namespaces
 * as {@link render}.
 *
 * Used for on-the-fly rendering of snippets stored outside the templates dir
 * (e.g. a fragment taken from a YAML schema or assembled in memory).
 *
 * @throws {TypeError} If the template renders to a non-string value.
 */
export function renderString(template, data) {
    const result = eta.renderString(template, buildTemplateContext(data));
    if (typeof result !== 'string') {
        throw new TypeError('Template renderString returned non-string');
    }
    return result;
}
/** Get the absolute path to the codegen templates directory. */
export function getTemplatesDir() {
    return TEMPLATES_DIR;
}
/** Get the absolute path to the base templates directory (parent of codegen). */
export function getBaseTemplatesDir() {
    return path.resolve(TEMPLATES_DIR, '..');
}
