import { resolve, sep } from 'node:path';
import { render } from 'ejs';
import { format } from 'prettier';
import { formatCommand } from './utils.js';
import { getPackageManagerExecuteCommand, getPackageManagerInstallCommand, getPackageManagerScriptCommand, } from './package-manager.js';
import { relativePath } from './file-helpers.js';
function convertDotFilesAndPaths(path) {
    return path
        .split(sep)
        .map((segment) => segment.replace(/^_dot_/, '.'))
        .join(sep);
}
function normalizeSourceExtension(target, typescript) {
    if (!typescript) {
        return target;
    }
    const normalizedTarget = target.replace(/\\/g, '/');
    if (!normalizedTarget.startsWith('src/')) {
        return target;
    }
    if (normalizedTarget.endsWith('.js')) {
        return `${target.slice(0, -3)}.ts`;
    }
    if (normalizedTarget.endsWith('.jsx')) {
        return `${target.slice(0, -4)}.tsx`;
    }
    return target;
}
export function createTemplateFile(environment, options) {
    function getPackageManagerAddScript(packageName, isDev = false) {
        return formatCommand(getPackageManagerInstallCommand(options.packageManager, packageName, isDev));
    }
    function getPackageManagerRunScript(scriptName, args = []) {
        return formatCommand(getPackageManagerScriptCommand(options.packageManager, [
            scriptName,
            ...args,
        ]));
    }
    function getPackageManagerExecuteScript(pkg, args = []) {
        return formatCommand(getPackageManagerExecuteCommand(options.packageManager, pkg, args));
    }
    class IgnoreFileError extends Error {
        constructor() {
            super('ignoreFile');
            this.name = 'IgnoreFileError';
        }
    }
    // Collect integrations and tag them with source add-on for attribution
    const integrations = [];
    for (const addOn of options.chosenAddOns) {
        if (addOn.integrations) {
            for (const integration of addOn.integrations) {
                integrations.push({
                    ...integration,
                    _sourceId: addOn.id,
                    _sourceName: addOn.name,
                });
            }
        }
    }
    const routes = [];
    for (const addOn of options.chosenAddOns) {
        if (addOn.routes) {
            routes.push(...addOn.routes);
        }
    }
    const addOnEnabled = options.chosenAddOns.reduce((acc, addOn) => {
        acc[addOn.id] = true;
        return acc;
    }, {});
    return async function templateFile(file, content) {
        const localRelativePath = (path, stripExtension = false) => relativePath(file, path, stripExtension);
        const integrationImportContent = (integration) => integration.import ||
            `import ${integration.jsName} from '${localRelativePath(integration.path || '')}'`;
        const integrationImportCode = (integration) => integration.code || integration.jsName;
        const templateValues = {
            packageManager: options.packageManager,
            projectName: options.projectName,
            typescript: true,
            tailwind: true,
            js: 'ts',
            jsx: 'tsx',
            fileRouter: options.mode === 'file-router',
            codeRouter: options.mode === 'code-router',
            routerOnly: options.routerOnly === true,
            includeExamples: options.includeExamples !== false,
            addOnEnabled,
            addOnOption: options.addOnOptions,
            addOns: options.chosenAddOns,
            integrations,
            routes,
            getPackageManagerAddScript,
            getPackageManagerRunScript,
            getPackageManagerExecuteScript,
            relativePath: (path, stripExtension = false) => relativePath(file, path, stripExtension),
            integrationImportContent,
            integrationImportCode,
            renderTemplate: (content) => {
                return render(content, templateValues);
            },
            ignoreFile: () => {
                throw new IgnoreFileError();
            },
        };
        let ignoreFile = false;
        if (file.endsWith('.ejs')) {
            try {
                content = render(content, templateValues);
            }
            catch (error) {
                if (error instanceof IgnoreFileError) {
                    ignoreFile = true;
                }
                else {
                    console.error(file, error);
                    environment.error(`EJS error in file ${file}`, error?.toString());
                    process.exit(1);
                }
            }
        }
        if (ignoreFile) {
            return;
        }
        let target = convertDotFilesAndPaths(file.replace('.ejs', ''));
        target = normalizeSourceExtension(target, options.typescript);
        // Strip option prefixes from filename (e.g., __postgres__schema.prisma -> schema.prisma)
        const prefixMatch = target.match(/^(.+\/)?__([^_]+)__(.+)$/);
        if (prefixMatch) {
            const [, directory, , filename] = prefixMatch;
            target = (directory || '') + filename;
        }
        let append = false;
        if (target.endsWith('.append')) {
            append = true;
            target = target.replace('.append', '');
        }
        if (target.endsWith('.ts') || target.endsWith('.tsx')) {
            content = await format(content, {
                semi: false,
                singleQuote: true,
                trailingComma: 'all',
                parser: 'typescript',
            });
        }
        if (append) {
            await environment.appendFile(resolve(options.targetDir, target), content);
        }
        else {
            await environment.writeFile(resolve(options.targetDir, target), content);
        }
    };
}
