import { existsSync, writeFileSync } from "node:fs";
import { mkdir, readFile, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import path, { basename, dirname, extname, join, relative } from "node:path";
import { confirm } from "@inquirer/prompts";
import { mergeOpenApiDocuments } from "@zuplo/openapi-tools";
import jsYaml from "js-yaml";
import { format } from "prettier";
import { logger } from "../../common/logger.js";
import { printCriticalFailureToConsoleAndExit, printDiagnosticsToConsole, printResultToConsoleAndExitGracefully, } from "../../common/output.js";
import { addOperationIdsAsNecessary, parseOpenApiFile } from "./utils.js";
export const BASE_TEMPLATE = `
{
  "openapi": "3.1.0",
  "info": {
    "version": "1.0.0",
    "title": "My Zuplo API"
  },
  "paths": {}
}

`;
export async function importOpenApi(argv) {
    let normalizedFilePath;
    let handleAsUrl = true;
    try {
        new URL(argv.source);
    }
    catch {
        handleAsUrl = false;
    }
    if (handleAsUrl) {
        const parsedUrl = new URL(argv.source);
        const tempDir = tmpdir();
        const guessedFileName = basename(parsedUrl.pathname).replace(/\.[^/.]+$/, "") ||
            `imported-${Buffer.from(argv.source).toString("base64")}`;
        normalizedFilePath = join(tempDir, guessedFileName);
        await mkdir(dirname(normalizedFilePath), { recursive: true });
        try {
            const response = await fetch(parsedUrl);
            if (!response.ok) {
                await printCriticalFailureToConsoleAndExit(`Failed to download the remote OpenAPI file. Server responded with ${response.status} ${response.statusText}`);
            }
            const text = await response.text();
            try {
                JSON.parse(text);
                normalizedFilePath = normalizedFilePath + ".json";
                await writeFile(normalizedFilePath, text, { flag: "w+" });
            }
            catch {
                try {
                    jsYaml.load(text);
                    normalizedFilePath = normalizedFilePath + ".yaml";
                    await writeFile(normalizedFilePath, text, { flag: "w+" });
                }
                catch {
                    await printCriticalFailureToConsoleAndExit(`Failed to parse the remote OpenAPI file as either JSON or YAML.`);
                }
            }
        }
        catch (err) {
            logger.error(err);
            await printCriticalFailureToConsoleAndExit(`Failed to download the remote OpenAPI file.`);
        }
    }
    else {
        const filePath = argv.source;
        normalizedFilePath = join(relative(process.cwd(), filePath));
        if (!existsSync(normalizedFilePath)) {
            await printCriticalFailureToConsoleAndExit(`The file ${normalizedFilePath} to import does not exist.`);
        }
    }
    const rawOpenApiSpec = await readFile(normalizedFilePath);
    const extName = extname(normalizedFilePath);
    const fileContent = rawOpenApiSpec.toString();
    const parsedOpenApiSpec = await parseOpenApiFile(extName, fileContent);
    const destination = argv.destination;
    if (!destination.endsWith(".oas.json")) {
        await printCriticalFailureToConsoleAndExit(`Destination file name must end with '.oas.json'`);
    }
    const destinationFilePath = join(relative(process.cwd(), destination));
    let originalDocument;
    if (!existsSync(destinationFilePath)) {
        originalDocument = (await parseOpenApiFile(".json", BASE_TEMPLATE));
    }
    else {
        const existingOpenApiSpec = await readFile(destinationFilePath);
        const existingFileContent = existingOpenApiSpec.toString();
        originalDocument = (await parseOpenApiFile(extName, existingFileContent));
    }
    const mergeMode = argv["merge-mode"] || "path-method";
    const { created, merged, retained, mergedDocument } = mergeOpenApiDocuments(originalDocument, parsedOpenApiSpec, mergeMode);
    printDiagnosticsToConsole("This import will...");
    printDiagnosticsToConsole("");
    if (created.size > 0) {
        printDiagnosticsToConsole(`Create ${created.size} new ${created.size > 1 ? "operations" : "operation"}`);
        printDiagnosticsToConsole("");
        created.forEach((operation) => {
            printDiagnosticsToConsole(operation);
        });
        printDiagnosticsToConsole("");
    }
    if (merged.size > 0) {
        printDiagnosticsToConsole(`Merge ${merged.size} ${merged.size > 1 ? "operations" : "operation"}`);
        printDiagnosticsToConsole("");
        merged.forEach((operation) => {
            printDiagnosticsToConsole(operation);
        });
        printDiagnosticsToConsole("");
    }
    if (retained.size > 0) {
        printDiagnosticsToConsole(`Retain ${retained.size} ${retained.size > 1 ? "operations" : "operation"}`);
        printDiagnosticsToConsole("");
        retained.forEach((operation) => {
            printDiagnosticsToConsole(operation);
        });
        printDiagnosticsToConsole("");
    }
    if (argv.prompt) {
        printDiagnosticsToConsole("");
        const answer = await confirm({ message: "Proceed?", default: true });
        if (!answer) {
            await printResultToConsoleAndExitGracefully("Import cancelled.");
        }
    }
    addOperationIdsAsNecessary(mergedDocument);
    const formattedOpenApi = await format(JSON.stringify(mergedDocument), {
        parser: "json-stringify",
    });
    if (!existsSync(destinationFilePath)) {
        const dir = path.dirname(destinationFilePath);
        await mkdir(dir, { recursive: true });
    }
    writeFileSync(destinationFilePath, formattedOpenApi, {
        flag: "w",
    });
    await printResultToConsoleAndExitGracefully(`Import successful. File written to ${destinationFilePath}`);
}
//# sourceMappingURL=handler.js.map