/**
 * Serialize variables helpers
 *
 * - In actions: can upload to Convex storage (store + get + getUrl)
 * - In mutations: can only inline JSON or delete existing storage
 */

import type { Id } from '../../../_generated/dataModel';
import type { ActionCtx } from '../../../_generated/server';
import { createDebugLog } from '../../../lib/debug_log';

const debugLog = createDebugLog('DEBUG_WORKFLOW', '[Workflow]');

// Threshold: 400KB (accounts for ~2x Convex serialization overhead under 1MB limit)
export const SIZE_THRESHOLD = 400 * 1024;

export interface SerializeResult {
  serialized: string;
  storageId?: Id<'_storage'>;
}

/**
 * Shared core for the action-safe serializers: inline small JSON, otherwise
 * store the payload in Convex storage (immutable) and return a reference.
 * Storage is sticky once `oldStorageId` is set; `debugLabel` keeps each
 * caller's existing log line intact.
 */
export async function serializeToStorage(
  ctx: ActionCtx,
  value: unknown,
  oldStorageId: Id<'_storage'> | undefined,
  debugLabel: string,
): Promise<SerializeResult> {
  const json = JSON.stringify(value ?? {});
  const sizeInBytes = new Blob([json]).size;

  const mustUseStorage = !!oldStorageId; // sticky once in storage
  const shouldUseStorage = mustUseStorage || sizeInBytes >= SIZE_THRESHOLD;

  debugLog(debugLabel, {
    sizeInBytes,
    threshold: SIZE_THRESHOLD,
    mustUseStorage,
    willUseStorage: shouldUseStorage,
  });

  if (!shouldUseStorage) {
    // Inline JSON. No deletes here to avoid races.
    return { serialized: json };
  }

  // Always store to storage (Convex storage is immutable).
  // Do NOT delete the old storage file here; the mutation will delete it after DB patch.
  const blob = new Blob([json], { type: 'application/json' });
  const storageId = await ctx.storage.store(blob);

  return {
    serialized: JSON.stringify({ _storageRef: storageId }),
    storageId,
  };
}

/**
 * Action-safe serializer: stores large payloads in Convex storage and returns a reference.
 */
export async function serializeVariables(
  ctx: ActionCtx,
  variables: Record<string, unknown> | undefined | null,
  oldStorageId?: Id<'_storage'>,
): Promise<SerializeResult> {
  return serializeToStorage(
    ctx,
    variables,
    oldStorageId,
    'serializeVariables Variable size:',
  );
}
