/*!
 * Copyright (C) Microsoft Corporation. All rights reserved.
 */
import prettier from 'prettier';
import { Project, ts } from 'ts-morph';
import { defaultPrettierConfig } from './defaultPrettierConfig.js';
const defaultCompilerOptions = {
    target: ts.ScriptTarget.ES2020,
    module: ts.ModuleKind.ESNext,
};
const COPYRIGHT_BANNER = [
    '/*!',
    ' * Copyright (C) Microsoft Corporation. All rights reserved.',
    ' * This file is autogenerated. Do not edit this file directly.',
    ' */',
    '',
    '',
].join('\n');
/*
  Compatibility layer for V1 and V2 codegen projects. The purpose of this class is
  purely to allow V1 modelServiceGenerator to use ts-morph backend without modification.
*/
export class CodegenV2Project {
    vfs;
    logger;
    tsMorphProject;
    fileMap;
    constructor(vfs, logger, compilerOptions) {
        this.vfs = vfs;
        this.logger = logger;
        const _compilerOptions = compilerOptions ?? defaultCompilerOptions;
        this.tsMorphProject = new Project({
            useInMemoryFileSystem: true,
            compilerOptions: _compilerOptions,
        });
        this.logger?.trackActivityEvent('Codegenv2.project.constructor', {
            message: 'Project created',
            compilerOptions: _compilerOptions,
        });
        this.fileMap = new Map();
    }
    async createFile(identifier, filePath, content) {
        const sourceFile = this.tsMorphProject.createSourceFile(filePath, content, { overwrite: true });
        if (this.fileMap.has(identifier)) {
            this.logger?.trackActivityEvent('Codegenv2.project.createFile.duplicateIdentifier', {
                message: `File with identifier ${identifier} already exists. Overwriting previous file.`,
                identifier,
                file: sourceFile.getBaseName(),
            });
        }
        this.fileMap.set(identifier, sourceFile);
        return sourceFile;
    }
    async commit() {
        const scenario = this.logger?.trackScenario('Codegenv2.project.commit');
        const normalizedContent = await Promise.all(this.tsMorphProject
            .getSourceFiles()
            .map((sourceFile) => this.normalizeFile(sourceFile, scenario)));
        // Write all to Vfs (stops on first error)
        let writtenCount = 0;
        try {
            for (const { path, content } of normalizedContent) {
                await this.vfs.writeFile(path, content);
                writtenCount++;
            }
        }
        catch (error) {
            scenario?.failure({
                message: 'Failed to commit all files to Vfs',
                error: this.logger?.stringifyError(error),
                filesWritten: writtenCount,
                totalFiles: normalizedContent.length,
                failedFile: normalizedContent[writtenCount]?.path,
            });
            throw error;
        }
        scenario?.complete({
            message: 'Successfully committed files to Vfs',
            filesWritten: writtenCount,
            totalFiles: normalizedContent.length,
        });
    }
    join(...paths) {
        return this.vfs.join(...paths);
    }
    async fileExists(path) {
        return !!this.tsMorphProject.getSourceFile(path);
    }
    async directoryExists(path) {
        return !!this.tsMorphProject.getDirectory(path);
    }
    async getSourceFilesInDirectory(path) {
        const directory = this.tsMorphProject.getDirectory(path);
        if (!directory) {
            return [];
        }
        return directory.getSourceFiles().map((file) => file.getBaseName());
    }
    getSourceFile(identifier) {
        const result = this.fileMap.get(identifier);
        if (!result) {
            throw new Error(`File with identifier ${identifier} not found. Possibly fetched before creation.`);
        }
        return result;
    }
    async normalizeFile(sourceFile, scenario) {
        const rawContent = sourceFile.getFullText();
        const path = sourceFile.getFilePath();
        // 1. Insert copyright banner if not present
        if (!rawContent.includes(COPYRIGHT_BANNER.trim())) {
            sourceFile.insertText(0, COPYRIGHT_BANNER);
        }
        // 2. Fix missing imports and organize them
        try {
            sourceFile.fixMissingImports();
            sourceFile.organizeImports();
        }
        catch (error) {
            scenario?.failure({
                message: 'Failed to organize and fix missing imports',
                file: sourceFile.getBaseName(),
            });
            throw error;
        }
        // 3. Run prettier
        let content;
        try {
            content = await prettier.format(sourceFile.getFullText(), {
                ...defaultPrettierConfig,
                parser: 'typescript',
            });
        }
        catch (error) {
            scenario?.failure({
                message: 'Failed to format files with Prettier',
                file: sourceFile.getBaseName(),
            });
            const e = error;
            console.error('Prettier formatting error:', e.message, e.codeFrame ?? '');
            throw error;
        }
        return { content, path };
    }
}
//# sourceMappingURL=project.js.map