"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.executeLT = executeLT;
const hotmesh_1 = require("@hotmeshio/hotmesh");
const interceptorActivities = __importStar(require("../interceptor/activities"));
const context_1 = require("../interceptor/context");
const defaults_1 = require("../../modules/defaults");
/**
 * Default activity queue for LT interceptor operations.
 * Must match the queue used when registering the activity worker.
 */
const LT_ACTIVITY_QUEUE = 'lt-interceptor';
/**
 * Execute a Long Tail workflow with automatic task tracking.
 *
 * Uses `startChild` to spawn the child workflow (fire-and-forget),
 * then `waitFor` to receive the result signal from the child's
 * interceptor. The child can escalate, fail, and be re-run multiple
 * times without affecting the parent — the orchestrator simply waits
 * for the signal.
 *
 * Usage (from within an orchestrator workflow):
 * ```typescript
 * export async function myPipeline(envelope: LTEnvelope) {
 *   return await executeLT({
 *     workflowName: 'reviewContent',
 *     args: [envelope],
 *     taskQueue: 'long-tail-examples',
 *     originId: envelope.data.orderId,
 *   });
 * }
 * ```
 */
async function executeLT(options) {
    const { workflowName, args, taskQueue, expire } = options;
    const { ltCreateTask, ltStartTask, ltCompleteTask, ltGetWorkflowConfig, ltGetProviderData, } = hotmesh_1.Durable.workflow.proxyActivities({
        activities: interceptorActivities,
        taskQueue: LT_ACTIVITY_QUEUE,
        retry: { maximumAttempts: 3 },
    });
    // Derive child workflow ID deterministically from the parent context.
    // Combines parent workflowId (globally unique) with the execution
    // counter (unique per step within this workflow) — zero-cost, fully
    // replay-safe, and self-documents its lineage.
    const ctx = hotmesh_1.Durable.workflow.workflowInfo();
    const childWorkflowId = options.workflowId || `${workflowName}-${ctx.workflowId}-${ctx.counter}`;
    const signalId = `lt-result-${childWorkflowId}`;
    // Read orchestrator context (set by interceptor wrapping the container)
    const orchCtx = (0, context_1.getOrchestratorContext)();
    // Derive lineage: originId traces back to the root workflow,
    // parentId identifies the immediate parent orchestrator.
    const envelope0 = args[0];
    const originId = options.originId
        || envelope0?.lt?.originId
        || orchCtx?.workflowId
        || childWorkflowId;
    const parentId = orchCtx?.workflowId || childWorkflowId;
    // 1. Create task record with routing metadata for the interceptor
    const taskId = await ltCreateTask({
        workflowId: childWorkflowId,
        workflowType: workflowName,
        ltType: workflowName,
        taskQueue,
        signalId,
        parentWorkflowId: orchCtx?.workflowId || childWorkflowId,
        originId,
        parentId,
        envelope: JSON.stringify(args[0] || {}),
        metadata: orchCtx
            ? {
                signalId,
                parentWorkflowId: orchCtx.workflowId,
                parentTaskQueue: orchCtx.taskQueue,
                parentWorkflowType: orchCtx.workflowType,
            }
            : { signalId },
        traceId: ctx.workflowTrace || undefined,
        spanId: ctx.workflowSpan || undefined,
        initiatedBy: orchCtx?.userId || envelope0?.lt?.userId,
    });
    await ltStartTask(taskId);
    // 2. Load workflow config for provider injection
    const wfConfig = await ltGetWorkflowConfig(workflowName);
    // 3. Inject provider data into envelope if consumes are configured
    if (wfConfig?.consumes?.length && originId) {
        const providerData = await ltGetProviderData({
            workflowName,
            originId,
        });
        const envelope = args[0];
        if (envelope && Object.keys(providerData).length > 0) {
            envelope.lt = { ...envelope.lt, providers: providerData };
        }
    }
    // 4. Inject task ID, lineage, and user context into the envelope so the
    //    interceptor can find the task and propagate identity to child workflows
    const envelope = args[0];
    if (envelope) {
        const userId = envelope.lt?.userId || orchCtx?.userId;
        envelope.lt = { ...envelope.lt, taskId, originId, parentId, userId };
        // Propagate certified flag from parent to child
        if (envelope0?.metadata?.certified === true && envelope.metadata) {
            envelope.metadata.certified = true;
        }
    }
    // 5. Start child workflow (fire-and-forget — only the start is awaited)
    await hotmesh_1.Durable.workflow.startChild({
        workflowName,
        args,
        taskQueue,
        workflowId: childWorkflowId,
        expire: expire || defaults_1.JOB_EXPIRE_SECS,
        entity: workflowName,
        signalIn: false,
    });
    // 6. Wait for the child's interceptor to signal back with the result
    const result = await hotmesh_1.Durable.workflow.condition(signalId);
    // 7. Complete the task — persist result data
    await ltCompleteTask({
        taskId,
        data: JSON.stringify(result?.data),
        milestones: result?.milestones || [],
        workflowId: childWorkflowId,
        workflowName,
        taskQueue,
    });
    return result;
}
