import { WorkflowInstance } from "../data/entities.js";
import { logWorkflowEvent } from "../lib/event-logger.js";
import {
  executeSendEmail,
  executeCallApi,
  executeEmitEvent,
  executeUpdateEntity,
  executeCallWebhook,
  executeFunction
} from "../lib/activity-executor.js";
import { createLogger } from "@open-mercato/shared/lib/logger";
const logger = createLogger("workflows").child({ component: "activity-worker" });
const WORKFLOW_ACTIVITIES_QUEUE = "workflow-activities";
const DEFAULT_CONCURRENCY = 1;
const envConcurrency = process.env.WORKERS_WORKFLOW_ACTIVITIES_CONCURRENCY;
const metadata = {
  queue: WORKFLOW_ACTIVITIES_QUEUE,
  id: "workflows:workflow-activities",
  concurrency: envConcurrency ? parseInt(envConcurrency, 10) : DEFAULT_CONCURRENCY
};
async function handle(job, ctx) {
  const { payload } = job;
  const startTime = Date.now();
  const em = ctx.resolve("em");
  const container = ctx;
  if (payload.kind === "timer") {
    logger.debug("Firing timer for instance", { instanceId: payload.workflowInstanceId, jobId: ctx.jobId });
    const { fireTimer } = await import("../lib/timer-handler.js");
    await fireTimer(em, container, {
      instanceId: payload.workflowInstanceId,
      stepInstanceId: payload.stepInstanceId,
      branchInstanceId: payload.branchInstanceId,
      tenantId: payload.tenantId,
      organizationId: payload.organizationId,
      userId: payload.userId
    });
    return;
  }
  logger.debug("Processing activity", {
    activityId: payload.activityId,
    activityType: payload.activityType,
    instanceId: payload.workflowInstanceId,
    jobId: ctx.jobId,
    attemptNumber: ctx.attemptNumber
  });
  try {
    const instance = await em.findOne(WorkflowInstance, {
      id: payload.workflowInstanceId,
      tenantId: payload.tenantId,
      organizationId: payload.organizationId
    });
    if (!instance) {
      throw new Error(
        `Workflow instance ${payload.workflowInstanceId} not found (tenant: ${payload.tenantId}, org: ${payload.organizationId})`
      );
    }
    const activityContext = {
      workflowInstance: instance,
      workflowContext: payload.workflowContext,
      stepContext: payload.stepContext,
      stepInstanceId: payload.stepInstanceId,
      branchInstanceId: payload.branchInstanceId,
      userId: payload.userId
    };
    const executeActivityByType = async (signal) => {
      switch (payload.activityType) {
        case "SEND_EMAIL":
          return await executeSendEmail(payload.activityConfig, activityContext, container);
        case "CALL_API":
          return await executeCallApi(
            em,
            payload.activityConfig,
            activityContext,
            container,
            signal
          );
        case "EMIT_EVENT":
          return await executeEmitEvent(payload.activityConfig, activityContext, container);
        case "UPDATE_ENTITY":
          return await executeUpdateEntity(
            em,
            payload.activityConfig,
            activityContext,
            container
          );
        case "CALL_WEBHOOK":
          return await executeCallWebhook(payload.activityConfig, activityContext, { signal });
        case "EXECUTE_FUNCTION":
          return await executeFunction(payload.activityConfig, activityContext, container);
        case "WAIT":
          return { waited: true };
        default:
          throw new Error(`Unsupported activity type: ${payload.activityType}`);
      }
    };
    let result;
    if (payload.timeoutMs && payload.timeoutMs > 0) {
      const abortController = new AbortController();
      const timeoutId = setTimeout(() => {
        abortController.abort();
      }, payload.timeoutMs);
      try {
        result = await Promise.race([
          executeActivityByType(abortController.signal),
          new Promise(
            (_, reject) => setTimeout(
              () => reject(new Error(`Activity timeout after ${payload.timeoutMs}ms`)),
              payload.timeoutMs
            )
          )
        ]);
      } finally {
        clearTimeout(timeoutId);
      }
    } else {
      result = await executeActivityByType();
    }
    const executionTimeMs = Date.now() - startTime;
    await logWorkflowEvent(em, {
      workflowInstanceId: payload.workflowInstanceId,
      stepInstanceId: payload.stepInstanceId,
      branchInstanceId: payload.branchInstanceId,
      eventType: "ACTIVITY_COMPLETED",
      eventData: {
        activityId: payload.activityId,
        activityName: payload.activityName,
        activityType: payload.activityType,
        async: true,
        jobId: ctx.jobId,
        attemptNumber: ctx.attemptNumber,
        executionTimeMs,
        output: result
      },
      userId: payload.userId,
      tenantId: payload.tenantId,
      organizationId: payload.organizationId
    });
    logger.debug("Activity completed", {
      activityId: payload.activityId,
      activityType: payload.activityType,
      instanceId: payload.workflowInstanceId,
      executionTimeMs
    });
    await checkAndResumeWorkflow(em, ctx, payload.workflowInstanceId, payload.branchInstanceId);
  } catch (error) {
    const executionTimeMs = Date.now() - startTime;
    logger.error("Activity failed", {
      activityId: payload.activityId,
      activityType: payload.activityType,
      instanceId: payload.workflowInstanceId,
      attemptNumber: ctx.attemptNumber,
      err: error
    });
    await logWorkflowEvent(em, {
      workflowInstanceId: payload.workflowInstanceId,
      stepInstanceId: payload.stepInstanceId,
      branchInstanceId: payload.branchInstanceId,
      eventType: "ACTIVITY_FAILED",
      eventData: {
        activityId: payload.activityId,
        activityName: payload.activityName,
        activityType: payload.activityType,
        async: true,
        jobId: ctx.jobId,
        attemptNumber: ctx.attemptNumber,
        error: error.message,
        errorStack: error.stack,
        executionTimeMs
      },
      userId: payload.userId,
      tenantId: payload.tenantId,
      organizationId: payload.organizationId
    });
    const maxAttempts = payload.retryPolicy?.maxAttempts || 1;
    if (ctx.attemptNumber >= maxAttempts) {
      logger.error("Activity failed after all attempts - triggering workflow failure handling", {
        activityId: payload.activityId,
        activityType: payload.activityType,
        maxAttempts,
        instanceId: payload.workflowInstanceId
      });
      await checkAndResumeWorkflow(em, ctx, payload.workflowInstanceId, payload.branchInstanceId);
    }
    throw error;
  }
}
async function checkAndResumeWorkflow(em, ctx, workflowInstanceId, branchInstanceId) {
  const { resumeWorkflowAfterActivities } = await import("../lib/workflow-executor.js");
  const container = ctx;
  try {
    await resumeWorkflowAfterActivities(em, container, workflowInstanceId, branchInstanceId);
  } catch (error) {
    if (!error.message?.includes("Activities still pending")) {
      logger.error("Failed to resume workflow instance", { instanceId: workflowInstanceId, err: error });
    }
  }
}
export {
  handle as default,
  metadata
};
//# sourceMappingURL=workflow-activities.worker.js.map
