var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
    var useValue = arguments.length > 2;
    for (var i = 0; i < initializers.length; i++) {
        value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
    }
    return useValue ? value : void 0;
};
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
    function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
    var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
    var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
    var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
    var _, done = false;
    for (var i = decorators.length - 1; i >= 0; i--) {
        var context = {};
        for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
        for (var p in contextIn.access) context.access[p] = contextIn.access[p];
        context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
        var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
        if (kind === "accessor") {
            if (result === void 0) continue;
            if (result === null || typeof result !== "object") throw new TypeError("Object expected");
            if (_ = accept(result.get)) descriptor.get = _;
            if (_ = accept(result.set)) descriptor.set = _;
            if (_ = accept(result.init)) initializers.unshift(_);
        }
        else if (_ = accept(result)) {
            if (kind === "field") initializers.unshift(_);
            else descriptor[key] = _;
        }
    }
    if (target) Object.defineProperty(target, contextIn.name, descriptor);
    done = true;
};
import * as fs from "fs/promises";
import * as path from "path";
import { readAppApiYamlFile } from "@superblocksteam/util";
import { Paths } from "../../const.js";
import llmobs from "../../llmobs/index.js";
import { renderPath } from "../shared.js";
import { ApiBuilderTransformer } from "./shared.js";
const src = { apis: Paths.ApiYamls };
const dest = { apis: Paths.GeneratedApis };
/**
 * Integrations that are not yet supported by Clark's API generation.
 * These have complex semantics that require custom handling.
 *
 * Note: OpenAPI-derived integrations (airtable, github, slack, etc.) are NOT here
 * because they inherit from RestApi and are dynamically supported via
 * createExtendedPluginTypeDefinition in integration-types.ts.
 *
 * When adding support for a new integration, remove it from this list
 * and add an entry to INTEGRATION_TYPE_DEFINITIONS in integration-types.ts.
 */
export const UNSUPPORTED_INTEGRATIONS = [
    "cosmosdb",
    "couchbase",
    "redis",
    "confluent",
    "kafka",
    "kinesis",
    "redpanda",
    "superblocks-ocr",
    "workflow",
    "gsheets",
];
export const isApiSupported = llmobs.wrap({ kind: "task", name: "isApiSupported" }, _isApiSupported);
function _isApiSupported(blocks) {
    // recursively check for unsupported integrations in nested blocks
    const checkBlocksRecursively = (blocksToCheck) => {
        if (!blocksToCheck)
            return false;
        for (const block of blocksToCheck) {
            // check direct integration
            if (block.step?.integration &&
                UNSUPPORTED_INTEGRATIONS.includes(block.step.integration)) {
                return true;
            }
            // check nested blocks in loops, conditionals, etc.
            if (block.loop?.blocks && checkBlocksRecursively(block.loop.blocks)) {
                return true;
            }
            // check conditional blocks (if, else, elseIf)
            if (block.conditional?.if?.blocks &&
                checkBlocksRecursively(block.conditional.if.blocks)) {
                return true;
            }
            if (block.conditional?.else?.blocks &&
                checkBlocksRecursively(block.conditional.else.blocks)) {
                return true;
            }
            if (block.conditional?.elseIf) {
                for (const elseIfBlock of block.conditional.elseIf) {
                    if (elseIfBlock.blocks &&
                        checkBlocksRecursively(elseIfBlock.blocks)) {
                        return true;
                    }
                }
            }
            // check try/catch/finally blocks
            if (block.tryCatch?.try?.blocks &&
                checkBlocksRecursively(block.tryCatch.try.blocks)) {
                return true;
            }
            if (block.tryCatch?.catch?.blocks &&
                checkBlocksRecursively(block.tryCatch.catch.blocks)) {
                return true;
            }
            if (block.tryCatch?.finally?.blocks &&
                checkBlocksRecursively(block.tryCatch.finally.blocks)) {
                return true;
            }
        }
        return false;
    };
    const hasUnsupportedIntegration = checkBlocksRecursively(blocks || []);
    return !hasUnsupportedIntegration;
}
let YamlToApiBuilderTransformer = (() => {
    let _classSuper = ApiBuilderTransformer;
    let _instanceExtraInitializers = [];
    let _readMergedApi_decorators;
    let _transform_decorators;
    return class YamlToApiBuilderTransformer extends _classSuper {
        static {
            const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
            _readMergedApi_decorators = [llmobs.decorate({
                    kind: "task",
                    name: "YamlToApiBuilderTransformer.readMergedApi",
                })];
            _transform_decorators = [llmobs.decorate({
                    kind: "task",
                    name: "YamlToApiBuilderTransformer.transform",
                })];
            __esDecorate(this, null, _readMergedApi_decorators, { kind: "method", name: "readMergedApi", static: false, private: false, access: { has: obj => "readMergedApi" in obj, get: obj => obj.readMergedApi }, metadata: _metadata }, null, _instanceExtraInitializers);
            __esDecorate(this, null, _transform_decorators, { kind: "method", name: "transform", static: false, private: false, access: { has: obj => "transform" in obj, get: obj => obj.transform }, metadata: _metadata }, null, _instanceExtraInitializers);
            if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
        }
        config = __runInitializers(this, _instanceExtraInitializers);
        evalScript = "./dist/do-eval-to-sdk.js";
        constructor(config) {
            super(src, dest, config.templateRenderer);
            this.config = config;
        }
        async readMergedApi(pathParams) {
            const relativePath = renderPath(Paths.ApiYamls, pathParams);
            // TODO: move the following to the AppShell service
            const apiDir = path.join(this.config.appRootDirPath, path.dirname(relativePath));
            const parentDir = path.dirname(apiDir);
            return readAppApiYamlFile(parentDir, pathParams.apiName, false);
        }
        async transform(src) {
            // prepare the template
            const targetDir = await this.renderTemplate();
            const apisDir = path.join(targetDir, "src/to-sdk");
            let entryTemplate = await fs.readFile(path.join(apisDir, "__template__.ts"), "utf-8");
            // replace `entities` declaration in template
            entryTemplate = entryTemplate.replace("const entities = [];", () => `const entities = ${JSON.stringify(this.config.entityNames)};`);
            const processedApis = [];
            for (const apiYaml of src.apis) {
                const { api } = await this.readMergedApi(apiYaml.pathParams);
                // NOTE: @joeyagreco - we don't tell clark about apis that contain integrations that are not yet supported in superblocks-library-shim/index.ts
                if (!isApiSupported(api.blocks || [])) {
                    continue;
                }
                // replace `json` declaration in template
                const entry = entryTemplate.replace("const json = {};", () => `const json = ${JSON.stringify(api, null, 2)};`);
                const fileName = `${apiYaml.pathParams.apiName}.ts`;
                await fs.writeFile(path.join(apisDir, fileName), entry, "utf-8");
                // NOTE: @joeyagreco - for multipage, we will likely want to incorporate the pageName pathParam
                processedApis.push(apiYaml.pathParams.apiName);
            }
            const evalResult = await this.runEvaluation(targetDir);
            const sdkApis = Object.entries(evalResult).map(([apiFilePath, content]) => {
                const apiName = path.basename(apiFilePath, ".js");
                return {
                    pathParams: {
                        apiName: `${apiName}.ts`,
                    },
                    content,
                };
            });
            if (!this.config.skipCleanup) {
                await fs.rm(targetDir, { recursive: true, force: true });
            }
            return {
                apis: sdkApis,
            };
        }
    };
})();
export { YamlToApiBuilderTransformer };
//# sourceMappingURL=to-sdk-transformer.js.map