import { WorkflowEvent } from "../data/entities.js";
import { executeActivity } from "./activity-executor.js";
import { logWorkflowEvent } from "./event-logger.js";
import { createLogger } from "@open-mercato/shared/lib/logger";
const logger = createLogger("workflows");
async function compensateWorkflow(em, container, instance, definition, options = {}) {
  const {
    maxCompensations,
    continueOnError = true,
    userId
  } = options;
  instance.status = "COMPENSATING";
  await em.flush();
  await logWorkflowEvent(em, {
    workflowInstanceId: instance.id,
    eventType: "COMPENSATION_STARTED",
    eventData: {
      reason: instance.errorMessage,
      maxCompensations,
      continueOnError
    },
    userId,
    tenantId: instance.tenantId,
    organizationId: instance.organizationId
  });
  const completedActivities = await getCompletedActivitiesForCompensation(
    em,
    instance.id
  );
  const activitiesToCompensate = maxCompensations ? completedActivities.slice(0, maxCompensations) : completedActivities;
  const result = {
    status: "COMPLETED",
    totalActivities: completedActivities.length,
    compensatedActivities: 0,
    failedCompensations: [],
    errors: []
  };
  for (const event of activitiesToCompensate) {
    const activityId = event.eventData.activityId;
    const activityName = event.eventData.activityName;
    const activityDef = findActivityInDefinition(definition, activityId);
    if (!activityDef) {
      logger.warn("Activity not found in definition, skipping compensation", { activityId });
      continue;
    }
    if (!activityDef.compensation?.activityId) {
      continue;
    }
    const compensationActivityId = activityDef.compensation.activityId;
    const compensationDef = findActivityInDefinition(definition, compensationActivityId);
    if (!compensationDef) {
      logger.warn("Compensation activity not found, skipping", { compensationActivityId });
      result.failedCompensations.push(activityId);
      continue;
    }
    try {
      await logWorkflowEvent(em, {
        workflowInstanceId: instance.id,
        eventType: "COMPENSATION_ACTIVITY_STARTED",
        eventData: {
          originalActivityId: activityId,
          compensationActivityId,
          compensationActivityName: compensationDef.activityName
        },
        userId,
        tenantId: instance.tenantId,
        organizationId: instance.organizationId
      });
      const compensationResult = await executeActivity(em, container, compensationDef, {
        workflowInstance: instance,
        workflowContext: instance.context,
        userId
      });
      if (compensationResult.success) {
        result.compensatedActivities++;
        await logWorkflowEvent(em, {
          workflowInstanceId: instance.id,
          eventType: "COMPENSATION_ACTIVITY_COMPLETED",
          eventData: {
            originalActivityId: activityId,
            compensationActivityId,
            output: compensationResult.output,
            executionTimeMs: compensationResult.executionTimeMs
          },
          userId,
          tenantId: instance.tenantId,
          organizationId: instance.organizationId
        });
      } else {
        result.failedCompensations.push(activityId);
        result.errors?.push(`Failed to compensate ${activityName}: ${compensationResult.error}`);
        await logWorkflowEvent(em, {
          workflowInstanceId: instance.id,
          eventType: "COMPENSATION_ACTIVITY_FAILED",
          eventData: {
            originalActivityId: activityId,
            compensationActivityId,
            error: compensationResult.error
          },
          userId,
          tenantId: instance.tenantId,
          organizationId: instance.organizationId
        });
        if (!continueOnError) {
          result.status = "FAILED";
          break;
        }
      }
    } catch (error) {
      result.failedCompensations.push(activityId);
      result.errors?.push(`Exception compensating ${activityName}: ${error.message}`);
      await logWorkflowEvent(em, {
        workflowInstanceId: instance.id,
        eventType: "COMPENSATION_ACTIVITY_FAILED",
        eventData: {
          originalActivityId: activityId,
          compensationActivityId,
          error: error.message
        },
        userId,
        tenantId: instance.tenantId,
        organizationId: instance.organizationId
      });
      if (!continueOnError) {
        result.status = "FAILED";
        break;
      }
    }
  }
  if (result.failedCompensations.length > 0) {
    result.status = result.compensatedActivities > 0 ? "PARTIAL" : "FAILED";
  }
  instance.status = result.status === "COMPLETED" ? "COMPENSATED" : "FAILED";
  await em.flush();
  await logWorkflowEvent(em, {
    workflowInstanceId: instance.id,
    eventType: result.status === "COMPLETED" ? "COMPENSATION_COMPLETED" : result.status === "PARTIAL" ? "COMPENSATION_PARTIAL" : "COMPENSATION_FAILED",
    eventData: {
      totalActivities: result.totalActivities,
      compensatedActivities: result.compensatedActivities,
      failedCompensations: result.failedCompensations,
      errors: result.errors
    },
    userId,
    tenantId: instance.tenantId,
    organizationId: instance.organizationId
  });
  return result;
}
async function getCompletedActivitiesForCompensation(em, workflowInstanceId) {
  const events = await em.find(WorkflowEvent, {
    workflowInstanceId,
    eventType: "ACTIVITY_COMPLETED"
  }, {
    orderBy: { occurredAt: "DESC" }
    // Reverse chronological order
  });
  return events;
}
function findActivityInDefinition(definition, activityId) {
  for (const transition of definition.definition.transitions) {
    if (transition.activities) {
      const activity = transition.activities.find((a) => a.activityId === activityId);
      if (activity) return activity;
    }
  }
  if (definition.definition.activities) {
    return definition.definition.activities.find((a) => a.activityId === activityId);
  }
  return void 0;
}
function shouldCompensateActivity(activityDef) {
  return !!activityDef.compensation?.activityId;
}
export {
  compensateWorkflow,
  shouldCompensateActivity
};
//# sourceMappingURL=compensation-handler.js.map
