/**
 * Persist execution result to database
 */

import { isRecord } from '../../../../lib/utils/type-guards';
import { internal } from '../../../_generated/api';
import { ActionCtx } from '../../../_generated/server';
import { toId } from '../../../lib/type_cast_helpers';
import { serializeVariables } from '../serialization/serialize_variables';
import { StepDefinition, StepExecutionResult } from './types';

export async function persistExecutionResult(
  ctx: ActionCtx,
  executionId: string,
  baseVariables: Record<string, unknown>,
  result: StepExecutionResult,
  stepDef: StepDefinition,
  stepsMap: Record<string, unknown>,
  essentialLoop?: Record<string, unknown>,
): Promise<void> {
  const merged: Record<string, unknown> = {
    ...baseVariables,
    lastOutput: result.output,
    steps: stepsMap,
    // Merge set_variables output under the 'variables' namespace
    variables: {
      ...(isRecord(baseVariables.variables) ? baseVariables.variables : {}),
      ...result.variables,
    },
    // Extract and override loop variable to prevent large payloads and ensure correct loop restoration
    ...(essentialLoop ? { loop: essentialLoop as unknown } : {}),
    organizationId: stepDef.organizationId ?? baseVariables['organizationId'],
  };

  // Get current execution to retrieve old storage ID for cleanup
  const currentExecution = await ctx.runQuery(
    internal.wf_executions.internal_queries.getRawExecution,
    {
      executionId: toId<'wfExecutions'>(executionId),
    },
  );
  const oldStorageId = currentExecution?.variablesStorageId;

  // Pre-serialize variables in action context so large payloads go to storage
  // Pass oldStorageId to ensure proper cleanup when variables shrink below threshold
  const { serialized, storageId } = await serializeVariables(
    ctx,
    merged,
    oldStorageId,
  );

  await ctx.runMutation(
    internal.wf_executions.internal_mutations.updateExecutionVariables,
    {
      executionId: toId<'wfExecutions'>(executionId),
      variablesSerialized: serialized,
      variablesStorageId: storageId,
    },
  );
}
