/**
 * Code-generation manager functions — TypeScript ports of the Handlebars helpers:
 * importManager, constructorInjectorManager, returnTypeManager, indexesManager, variablesInjectorManager.
 */
import { toSnakeCase } from './string-utils.js';
/** Group imports by path, deduplicate items, sort, return formatted import/export string. */
export function importManager({ commandType = 'import', imports = [], sortImportedClasses = true, sortImports = true, }) {
    const grouped = new Map();
    for (const imp of imports) {
        const existing = grouped.get(imp.path);
        if (existing) {
            existing.push(imp);
        }
        else {
            grouped.set(imp.path, [imp]);
        }
    }
    const paths = [...grouped.keys()];
    if (sortImports) {
        paths.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
    }
    let response = '';
    for (const importPath of paths) {
        const pathImports = grouped.get(importPath);
        const masterImport = pathImports[0];
        const importsItems = [];
        for (const { items } of pathImports) {
            if (Array.isArray(items)) {
                for (const item of items) {
                    if (!importsItems.includes(item))
                        importsItems.push(item);
                }
            }
            else if (!importsItems.includes(items)) {
                importsItems.push(items);
            }
        }
        if (sortImportedClasses) {
            importsItems.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
        }
        if (masterImport.defaultImport) {
            response += `${commandType} ${importsItems[0]} from '${importPath}';\n`;
        }
        else if (masterImport.oneRowByItem) {
            response += `${commandType} {\n`;
            for (const item of importsItems) {
                response += `    ${item},\n`;
            }
            response += `} from '${importPath}';\n`;
        }
        else {
            response += `${commandType} { ${importsItems.join(', ')} } from '${importPath}';\n`;
        }
    }
    // Leading newline separates imports from preceding content (e.g. JSDoc) when slurp tags
    // (<%_ _%>) consume whitespace in templates.
    return response ? '\n' + response : response;
}
/** Deduplicate by variableName, sort, return formatted constructor parameters string. */
export function constructorInjectorManager({ injections = [], nTabulations = 2, sortInjections = true, }) {
    const tabulation = '    ';
    const deduped = [];
    for (const injection of injections) {
        if (!deduped.some((d) => d.variableName === injection.variableName)) {
            deduped.push({
                ...injection,
                readonly: injection.readonly ?? true,
                scope: injection.scope ?? 'private',
            });
        }
    }
    if (sortInjections) {
        deduped.sort((a, b) => a.variableName.toLowerCase().localeCompare(b.variableName.toLowerCase()));
    }
    let response = '';
    for (const [i, inj] of deduped.entries()) {
        const readonlyStr = inj.readonly ? 'readonly ' : '';
        response += `${tabulation.repeat(nTabulations)}${inj.scope} ${readonlyStr}${inj.variableName}: ${inj.className},`;
        if (i !== deduped.length - 1)
            response += '\n';
    }
    return response;
}
/** Deduplicate, sort, return formatted type declarations string. */
export function returnTypeManager({ nTabulations = 1, returnTypes = [], sortReturnTypes = true, }) {
    const tabulation = '    ';
    const deduped = [];
    for (const rt of returnTypes) {
        if (!deduped.some((d) => d.variableName === rt.variableName)) {
            deduped.push(rt);
        }
    }
    if (sortReturnTypes) {
        deduped.sort((a, b) => a.variableName.toLowerCase().localeCompare(b.variableName.toLowerCase()));
    }
    let response = '';
    for (const [i, rt] of deduped.entries()) {
        response += `${tabulation.repeat(nTabulations)}${rt.variableName}: ${rt.className};`;
        if (i !== deduped.length - 1)
            response += '\n';
    }
    return response;
}
/** Generate Sequelize index definitions from Property[]. */
export function indexesManager({ indexProperties = [], isI18n = false, }) {
    let props = indexProperties;
    if (isI18n) {
        props = props.filter((property) => property.isI18n === isI18n);
    }
    let response = '';
    for (const [i, indexProperty] of props.entries()) {
        response += '\t\t{\n';
        response += '\t\t\tfields: [';
        if (Array.isArray(indexProperty.indexFields)) {
            for (const [j, indexField] of indexProperty.indexFields.entries()) {
                if (j === indexProperty.indexFields.length - 1) {
                    response += `'${toSnakeCase(indexField)}'`;
                    continue;
                }
                response += `'${toSnakeCase(indexField)}', `;
            }
        }
        else {
            response += `'${toSnakeCase(indexProperty.name)}'`;
        }
        response += '],\n';
        response += `\t\t\tunique: ${indexProperty.index === 'unique' ? 'true' : 'false'},\n`;
        if (indexProperty.indexName)
            response += `\t\t\tname: '${toSnakeCase(indexProperty.indexName)}',\n`;
        if (indexProperty.indexUsing)
            response += `\t\t\tusing: '${indexProperty.indexUsing}',\n`;
        response += `\t\t},${i === props.length - 1 ? '' : '\n'}`;
    }
    return response;
}
/** Generate Angular `inject()` calls for dependency injection. */
export function variablesInjectorManager({ injections = [], nTabulations = 1, sortInjections = true, }) {
    const tabulation = '    ';
    const deduped = [];
    for (const injection of injections) {
        if (!deduped.some((d) => d.variableName === injection.variableName)) {
            deduped.push(injection);
        }
    }
    if (sortInjections) {
        deduped.sort((a, b) => a.variableName.toLowerCase().localeCompare(b.variableName.toLowerCase()));
    }
    let response = '';
    for (const [i, inj] of deduped.entries()) {
        response += `${tabulation.repeat(nTabulations)}const ${inj.variableName} = inject(${inj.className});`;
        if (i !== deduped.length - 1)
            response += '\n';
    }
    return response;
}
