"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildMergedYaml = void 0;
exports.getEngine = getEngine;
exports.deployAppId = deployAppId;
exports.deployYamlWorkflow = deployYamlWorkflow;
exports.activateYamlWorkflow = activateYamlWorkflow;
exports.invokeYamlWorkflow = invokeYamlWorkflow;
exports.invokeYamlWorkflowSync = invokeYamlWorkflowSync;
exports.stopEngine = stopEngine;
exports.stopAllEngines = stopAllEngines;
const hotmesh_1 = require("@hotmeshio/hotmesh");
const db_1 = require("../../lib/db");
const defaults_1 = require("../../modules/defaults");
const logger_1 = require("../../lib/logger");
const namespaceService = __importStar(require("../namespace"));
const deployer_helpers_1 = require("./deployer-helpers");
// Re-export helpers so existing `import * from './deployer'` consumers keep working
var deployer_helpers_2 = require("./deployer-helpers");
Object.defineProperty(exports, "buildMergedYaml", { enumerable: true, get: function () { return deployer_helpers_2.buildMergedYaml; } });
/** Cache of HotMesh engine instances keyed by appId */
const engines = new Map();
/**
 * Get or create a HotMesh engine instance for a given app ID.
 * Flows sharing the same appId share the same engine (and DB connection pool).
 */
async function getEngine(appId) {
    const cached = engines.get(appId);
    if (cached)
        return cached;
    const engine = await hotmesh_1.HotMesh.init({
        appId,
        guid: `deployer::${appId}-${hotmesh_1.HotMesh.guid()}`,
        engine: {
            connection: (0, db_1.getConnection)(),
        },
    });
    engines.set(appId, engine);
    return engine;
}
/**
 * Deploy all YAML workflows for an app_id as a single merged version.
 *
 * On failure, attempts one recompilation cycle:
 *   1. Identifies the workflow that was most recently compiled (the trigger)
 *   2. Re-runs the full compilation pipeline with the error as context
 *   3. The compile stage's LLM receives the error + failed YAML to avoid the same issue
 *   4. Stores the recompiled YAML and retries deployment
 *
 * If recompilation is unavailable or fails, the original error is thrown.
 */
async function deployAppId(appId, version) {
    await namespaceService.registerNamespace(appId);
    const mergedYaml = await (0, deployer_helpers_1.buildMergedYaml)(appId, version);
    logger_1.loggerRegistry.debug(`[yaml-workflow] merged YAML for ${appId} v${version}:\n${mergedYaml}`);
    const engine = await getEngine(appId);
    try {
        const manifest = await engine.deploy(mergedYaml);
        await engine.activate(version);
        logger_1.loggerRegistry.info(`[yaml-workflow] deployed+activated ${appId} v${version} (merged)`);
        return manifest;
    }
    catch (err) {
        logger_1.loggerRegistry.error(`[yaml-workflow] deployment failed for ${appId} v${version}: ${err.message}`);
        // Attempt recompilation with error context
        const recompiled = await (0, deployer_helpers_1.recompileWithContext)(appId, mergedYaml, err.message);
        if (!recompiled)
            throw err;
        // Rebuild merged YAML with the recompiled workflow and retry
        logger_1.loggerRegistry.info(`[yaml-workflow] retrying deployment after recompilation for ${appId}`);
        try {
            const retriedYaml = await (0, deployer_helpers_1.buildMergedYaml)(appId, version);
            const manifest = await engine.deploy(retriedYaml);
            await engine.activate(version);
            logger_1.loggerRegistry.info(`[yaml-workflow] recompilation succeeded — deployed+activated ${appId} v${version}`);
            return manifest;
        }
        catch (retryErr) {
            logger_1.loggerRegistry.error(`[yaml-workflow] recompilation retry also failed for ${appId}: ${retryErr.message}`);
            throw retryErr;
        }
    }
}
/**
 * Deploy a single YAML workflow to HotMesh (inactive until activated).
 * @deprecated Use deployAppId for merged deployment.
 */
async function deployYamlWorkflow(appId, yamlContent) {
    const engine = await getEngine(appId);
    const manifest = await engine.deploy(yamlContent);
    logger_1.loggerRegistry.info(`[yaml-workflow] deployed ${appId}`);
    return manifest;
}
/**
 * Activate a deployed version of a YAML workflow.
 */
async function activateYamlWorkflow(appId, version) {
    const engine = await getEngine(appId);
    const result = await engine.activate(version);
    logger_1.loggerRegistry.info(`[yaml-workflow] activated ${appId} v${version}`);
    return result;
}
/**
 * Invoke a YAML workflow (fire-and-forget). Returns the job ID.
 */
async function invokeYamlWorkflow(appId, topic, data, entity, context) {
    const engine = await getEngine(appId);
    return engine.pub(topic, data, context, entity ? { entity } : undefined);
}
/**
 * Invoke a YAML workflow and wait for the result.
 *
 * Replicates HotMesh's engine.pubsub() logic exactly, but adds the
 * `extended` parameter (where entity lives) to the internal pub() call.
 * HotMesh's pubsub omits extended, so entity was never set.
 *
 * Source: @hotmeshio/hotmesh engine/index.js pubsub()
 */
async function invokeYamlWorkflowSync(appId, topic, data, timeout, entity) {
    const hotmesh = await getEngine(appId);
    const engine = hotmesh.engine;
    const timeoutMs = timeout ?? defaults_1.WORKFLOW_SYNC_TIMEOUT_MS;
    // Build context with engine GUID for one-time subscription routing
    // (exactly as engine.pubsub does)
    const context = {
        metadata: {
            ngn: engine.guid,
        },
    };
    // Publish with entity via extended param
    const extended = entity ? { entity } : undefined;
    const jobId = await engine.pub(topic, data, context, extended);
    return new Promise((resolve, reject) => {
        engine.registerJobCallback(jobId, (_topic, output) => {
            if (output.metadata.err) {
                const error = JSON.parse(output.metadata.err);
                reject({ error, job_id: output.metadata.jid });
            }
            else {
                resolve({
                    job_id: jobId,
                    result: output,
                });
            }
        });
        setTimeout(() => {
            engine.delistJobCallback(jobId);
            reject({ code: 598, message: 'timeout', job_id: jobId });
        }, timeoutMs);
    });
}
/**
 * Stop a specific YAML workflow engine.
 */
async function stopEngine(appId) {
    const engine = engines.get(appId);
    if (engine) {
        await engine.stop();
        engines.delete(appId);
    }
}
/**
 * Stop all YAML workflow engines.
 */
async function stopAllEngines() {
    for (const [appId, engine] of engines) {
        await engine.stop();
        engines.delete(appId);
    }
}
