import { getNormalizedAbsolutePath, NoTarget, resolvePath, } from "@typespec/compiler";
import { promises } from "fs";
import { dump } from "js-yaml";
import { dirname } from "path";
import { fileURLToPath } from "url";
import { CodeModelBuilder } from "./code-model-builder.js";
import { LibName, reportDiagnostic } from "./lib.js";
import { DiagnosticError, spawnAsync, SpawnError, trace } from "./utils.js";
import { validateDependencies } from "./validate.js";
export async function $onEmit(context) {
    var _a, _b, _c, _d, _e, _f, _g, _h, _j;
    const program = context.program;
    if (!program.compilerOptions.noEmit) {
        await validateDependencies(program, true);
    }
    if (!program.hasError()) {
        const options = context.options;
        if (!options["flavor"]) {
            if (LibName === "@azure-tools/typespec-java") {
                options["flavor"] = "azure";
            }
        }
        let codeModel;
        try {
            const builder = new CodeModelBuilder(program, context);
            codeModel = await builder.build();
        }
        catch (error) {
            if (error instanceof DiagnosticError) {
                // diagnostic thrown as error
                program.reportDiagnostic(error.diagnostic);
            }
            else {
                // unknown error
                reportDiagnostic(program, {
                    code: "unknown-error",
                    format: {
                        errorMessage: `Error occurred when building the code model. The emitter was unable to generate client code from this TypeSpec, please open an issue on https://github.com/microsoft/typespec, include TypeSpec source and all the diagnostic information in your submission.\nStack: ${error.stack}\nError: ${error.toString()}`,
                    },
                    target: NoTarget,
                });
                trace(program, error.stack);
            }
        }
        if (codeModel && !program.hasError() && !program.compilerOptions.noEmit) {
            const __dirname = dirname(fileURLToPath(import.meta.url));
            const moduleRoot = resolvePath(__dirname, "..", "..");
            const outputPath = context.emitterOutputDir;
            options["output-dir"] = getNormalizedAbsolutePath(outputPath, undefined);
            options.arm = codeModel.arm;
            if ((_c = (_b = (_a = codeModel.info) === null || _a === void 0 ? void 0 : _a.license) === null || _b === void 0 ? void 0 : _b.extensions) === null || _c === void 0 ? void 0 : _c.header) {
                options["license-header"] = codeModel.info.license.extensions.header;
            }
            const codeModelFileName = resolvePath(outputPath, "./code-model.yaml");
            await promises.mkdir(outputPath, { recursive: true }).catch((err) => {
                if (err.code !== "EISDIR" && err.code !== "EEXIST") {
                    reportDiagnostic(program, {
                        code: "unknown-error",
                        format: { errorMessage: `Failed to create output directory: ${outputPath}.` },
                        target: NoTarget,
                    });
                    return;
                }
            });
            await program.host.writeFile(codeModelFileName, dump(codeModel));
            trace(program, `Code model file written to ${codeModelFileName}`);
            const emitterOptions = JSON.stringify(options);
            trace(program, `Emitter options ${emitterOptions}`);
            const jarFileName = resolvePath(moduleRoot, "generator/http-client-generator/target", "emitter.jar");
            trace(program, `Exec JAR ${jarFileName}`);
            const javaArgs = [];
            javaArgs.push(`-DemitterOptions=${emitterOptions}`);
            if ((_d = options["dev-options"]) === null || _d === void 0 ? void 0 : _d.debug) {
                javaArgs.push("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:5005");
            }
            if ((_e = options["dev-options"]) === null || _e === void 0 ? void 0 : _e.loglevel) {
                javaArgs.push("-Dorg.slf4j.simpleLogger.defaultLogLevel=" + ((_f = options["dev-options"]) === null || _f === void 0 ? void 0 : _f.loglevel));
            }
            if ((_g = options["dev-options"]) === null || _g === void 0 ? void 0 : _g["java-temp-dir"]) {
                javaArgs.push("-Dcodegen.java.temp.directory=" + ((_h = options["dev-options"]) === null || _h === void 0 ? void 0 : _h["java-temp-dir"]));
            }
            javaArgs.push("-jar");
            javaArgs.push(jarFileName);
            javaArgs.push(codeModelFileName);
            try {
                const result = await spawnAsync("java", javaArgs, { stdio: "pipe" });
                reportJarOutput(program, result.stdout);
                // trace(program, `Code generation log: ${result.stdout}`);
            }
            catch (error) {
                if (error && "code" in error && error["code"] === "ENOENT") {
                    reportDiagnostic(program, {
                        code: "invalid-java-sdk-dependency",
                        target: NoTarget,
                    });
                }
                else {
                    if (error instanceof SpawnError) {
                        reportJarOutput(program, error.stdout);
                        // trace(program, `Code generation log: ${error.stdout}`);
                    }
                    // error in Java codegen, report as unknown error
                    reportDiagnostic(program, {
                        code: "unknown-error",
                        format: {
                            errorMessage: `Error occurred while running Java generator. The emitter was unable to generate client code from this TypeSpec, please open an issue on https://github.com/microsoft/typespec, include TypeSpec source and all the diagnostic information in your submission. ${error.stack}\nError: ${error.toString()}`,
                        },
                        target: NoTarget,
                    });
                }
            }
            if (!((_j = options["dev-options"]) === null || _j === void 0 ? void 0 : _j["generate-code-model"])) {
                await program.host.rm(codeModelFileName);
            }
        }
    }
}
function reportJarOutput(program, jarOutput) {
    const lines = jarOutput.split("\n");
    const logs = [];
    // parse stdout to array of logs
    let currentLog = undefined;
    for (const line of lines) {
        if (line.startsWith("TRACE ") ||
            line.startsWith("DEBUG ") ||
            line.startsWith("INFO ") ||
            line.startsWith("WARN ") ||
            line.startsWith("ERROR ")) {
            if (currentLog) {
                logs.push(currentLog);
            }
            currentLog = line;
        }
        else if (currentLog) {
            currentLog = currentLog + "\n" + line;
        }
    }
    if (currentLog) {
        logs.push(currentLog);
    }
    // trace or report the logs, according to log level
    for (const log of logs) {
        if (log.startsWith("ERROR ")) {
            reportDiagnostic(program, {
                code: "generator-error",
                format: {
                    errorMessage: log.substring(6),
                },
                target: NoTarget,
            });
        }
        else if (log.startsWith("WARN ")) {
            reportDiagnostic(program, {
                code: "generator-warning",
                format: {
                    warningMessage: log.substring(5),
                },
                target: NoTarget,
            });
        }
        else {
            const index = log.indexOf(" ");
            trace(program, log.substring(index + 1));
        }
    }
}
//# sourceMappingURL=emitter.js.map