/**
 * Idempotency Key Utilities
 * 
 * Provides helper functions for generating and managing idempotency keys
 * for moderation operations to prevent duplicate requests.
 * 
 * Integrated with idempotencyLifecycle.ts for full lifecycle tracking.
 */

import {
  registerIdempotencyKey,
  updateIdempotencyStatus,
  getIdempotencyRecord,
  isIdempotencyKeyValid,
  type IdempotencyRecord,
} from './idempotencyLifecycle';

/**
 * Generate a deterministic idempotency key for a moderation action
 * 
 * Format: action_submissionId_itemIds_userId_timestamp
 * Example: approval_abc123_def456_ghi789_user123_1699564800000
 * 
 * @param action - The moderation action type ('approval', 'rejection', 'retry')
 * @param submissionId - The submission ID
 * @param itemIds - Array of item IDs being processed
 * @param userId - The moderator's user ID
 * @returns Deterministic idempotency key
 */
export function generateIdempotencyKey(
  action: 'approval' | 'rejection' | 'retry',
  submissionId: string,
  itemIds: string[],
  userId: string
): string {
  // Sort itemIds to ensure consistency regardless of order
  const sortedItemIds = [...itemIds].sort().join('_');
  
  // Include timestamp to allow same moderator to retry after 24h window
  const timestamp = Date.now();
  
  return `${action}_${submissionId}_${sortedItemIds}_${userId}_${timestamp}`;
}

/**
 * Check if an error is a 409 Conflict (duplicate request)
 * 
 * @param error - Error object to check
 * @returns True if error is 409 Conflict
 */
export function is409Conflict(error: unknown): boolean {
  if (!error || typeof error !== 'object') return false;
  
  const errorObj = error as { status?: number; message?: string };
  
  // Check status code
  if (errorObj.status === 409) return true;
  
  // Check error message for conflict indicators
  const message = errorObj.message?.toLowerCase() || '';
  return message.includes('duplicate request') || 
         message.includes('already in progress') ||
         message.includes('race condition');
}

/**
 * Extract retry-after value from error response
 * 
 * @param error - Error object with potential Retry-After header
 * @returns Seconds to wait before retry, defaults to 3
 */
export function getRetryAfter(error: unknown): number {
  if (!error || typeof error !== 'object') return 3;
  
  const errorObj = error as { 
    retryAfter?: number;
    context?: { headers?: { 'Retry-After'?: string } }
  };
  
  // Check structured retryAfter field
  if (errorObj.retryAfter) return errorObj.retryAfter;
  
  // Check Retry-After header
  const retryAfterHeader = errorObj.context?.headers?.['Retry-After'];
  if (retryAfterHeader) {
    const seconds = parseInt(retryAfterHeader, 10);
    return isNaN(seconds) ? 3 : seconds;
  }
  
  return 3; // Default 3 seconds
}

/**
 * Sleep for a specified duration
 * 
 * @param ms - Milliseconds to sleep
 */
export function sleep(ms: number): Promise<void> {
  return new Promise(resolve => setTimeout(resolve, ms));
}

/**
 * Generate and register a new idempotency key with lifecycle tracking
 * 
 * @param action - The moderation action type
 * @param submissionId - The submission ID
 * @param itemIds - Array of item IDs being processed
 * @param userId - The moderator's user ID
 * @returns Idempotency key and record
 */
export async function generateAndRegisterKey(
  action: 'approval' | 'rejection' | 'retry',
  submissionId: string,
  itemIds: string[],
  userId: string
): Promise<{ key: string; record: IdempotencyRecord }> {
  const key = generateIdempotencyKey(action, submissionId, itemIds, userId);
  const record = await registerIdempotencyKey(key, action, submissionId, itemIds, userId);
  
  return { key, record };
}

/**
 * Validate and mark idempotency key as processing
 * 
 * @param key - Idempotency key to validate
 * @returns True if valid and marked as processing
 */
export async function validateAndStartProcessing(key: string): Promise<boolean> {
  const isValid = await isIdempotencyKeyValid(key);
  
  if (!isValid) {
    return false;
  }
  
  const record = await getIdempotencyRecord(key);
  
  // Only allow transition from pending to processing
  if (record?.status !== 'pending') {
    return false;
  }
  
  await updateIdempotencyStatus(key, 'processing');
  return true;
}

/**
 * Mark idempotency key as completed
 */
export async function markKeyCompleted(key: string): Promise<void> {
  await updateIdempotencyStatus(key, 'completed');
}

/**
 * Mark idempotency key as failed
 */
export async function markKeyFailed(key: string, error: string): Promise<void> {
  await updateIdempotencyStatus(key, 'failed', error);
}
