/** Shared utilities for back and front handlers. */
import * as fs from 'node:fs';
import path, { join } from 'node:path';
import { GENDER, PROPERTY_TYPE, RELATIONSHIP_TYPE } from '../domain/config.js';
import { WidgetType } from '../domain/widget-type.js';
import { hasI18nProperties } from '../domain/property-filters.js';
export const logger = console;
const SKIP_COPY = new Set(['coverage', 'dist', 'node_modules']);
/**
 * Recursively copies `src` into `dest`.
 *
 * @param src   - Source directory.
 * @param dest  - Destination directory (created if absent).
 * @param force - When `false` (default) a file that already exists in `dest`
 *                is SKIPPED (preserved); the destination path is collected and
 *                returned so the caller can report it to the user.
 *                When `true` every file is overwritten unconditionally
 *                (previous behaviour, used by application-scaffold copies).
 * @returns Array of absolute destination paths that were skipped.
 */
export function copyDirRecursive(src, dest, force = false) {
    if (!fs.existsSync(dest))
        fs.mkdirSync(dest, { recursive: true });
    const skipped = [];
    for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
        if (SKIP_COPY.has(entry.name))
            continue;
        const srcPath = path.join(src, entry.name);
        const destPath = path.join(dest, entry.name);
        if (entry.isDirectory()) {
            const childSkipped = copyDirRecursive(srcPath, destPath, force);
            skipped.push(...childSkipped);
        }
        else if (!force && fs.existsSync(destPath)) {
            skipped.push(destPath);
        }
        else {
            fs.copyFileSync(srcPath, destPath);
        }
    }
    return skipped;
}
export function ensureDir(baseDir, relativePath) {
    const absolute = join(process.cwd(), baseDir, relativePath);
    if (!fs.existsSync(absolute)) {
        fs.mkdirSync(absolute, { recursive: true });
    }
}
export function buildOptions(schema, ctx) {
    return {
        boundedContextName: schema.boundedContextName,
        excludedFiles: schema.excludedFiles,
        excludedOperations: schema.excludedOperations,
        force: ctx.flags.force,
        lockFiles: ctx.lockFiles,
        moduleName: schema.moduleName,
        moduleNames: schema.moduleNames,
        templateData: {
            gender: GENDER,
            // Pre-resolved key into the global i18n gendered entries (`{ F: "Nueva", M: "Nuevo" }`).
            // Templates concatenate as `t('New.<%= it.genderKey %>')`. Falls back to `'M'` when the
            // schema has no `front` (e.g. pivots).
            genderKey: schema.front?.gender === GENDER.FEMININE ? 'F' : 'M',
            isI18n: hasI18nProperties(schema.aggregateProperties),
            propertyType: PROPERTY_TYPE,
            relationshipType: RELATIONSHIP_TYPE,
            schema,
            widgetType: WidgetType,
        },
        verbose: ctx.flags.verbose,
    };
}
export function buildPropertyOptions(baseOptions, property) {
    return {
        ...baseOptions,
        currentProperty: property,
        templateData: {
            ...baseOptions.templateData,
            moduleNamePrefix: '',
            moduleNameSuffix: property.isI18n ? 'I18n' : '',
        },
    };
}
