/**
 * Edge Function Request Tracking Wrapper
 * 
 * Wraps Supabase function invocations with request tracking for debugging and monitoring.
 * Provides correlation IDs for tracing requests across the system.
 */

import { supabase } from '@/integrations/supabase/client';
import { trackRequest } from './requestTracking';
import { getErrorMessage } from './errorHandler';

/**
 * Invoke a Supabase edge function with request tracking
 * 
 * @param functionName - Name of the edge function to invoke
 * @param payload - Request payload
 * @param userId - User ID for tracking (optional)
 * @param parentRequestId - Parent request ID for chaining (optional)
 * @param traceId - Trace ID for distributed tracing (optional)
 * @returns Response data with requestId
 */
export async function invokeWithTracking<T = any>(
  functionName: string,
  payload: any = {},
  userId?: string,
  parentRequestId?: string,
  traceId?: string,
  timeout: number = 30000 // Default 30s timeout
): Promise<{ data: T | null; error: any; requestId: string; duration: number }> {
  // Create AbortController for timeout
  const controller = new AbortController();
  const timeoutId = setTimeout(() => controller.abort(), timeout);
  
  try {
    const { result, requestId, duration } = await trackRequest(
      {
        endpoint: `/functions/${functionName}`,
        method: 'POST',
        userId,
        parentRequestId,
        traceId,
      },
      async (context) => {
        // Include client request ID in payload for correlation
        const { data, error } = await supabase.functions.invoke<T>(functionName, {
          body: { ...payload, clientRequestId: context.requestId },
          signal: controller.signal, // Add abort signal for timeout
        });

        if (error) throw error;
        return data;
      }
    );

    clearTimeout(timeoutId);
    return { data: result, error: null, requestId, duration };
  } catch (error: unknown) {
    clearTimeout(timeoutId);
    
    // Handle AbortError specifically
    if (error instanceof Error && error.name === 'AbortError') {
      return {
        data: null,
        error: { 
          message: `Request timeout: ${functionName} took longer than ${timeout}ms to respond`,
          code: 'TIMEOUT',
        },
        requestId: 'timeout',
        duration: timeout,
      };
    }
    
    const errorMessage = getErrorMessage(error);
    return {
      data: null,
      error: { message: errorMessage },
      requestId: 'unknown',
      duration: 0,
    };
  }
}

/**
 * Invoke multiple edge functions in parallel with batch tracking
 * 
 * Uses a shared trace ID to correlate all operations.
 * 
 * @param operations - Array of function invocation configurations
 * @param userId - User ID for tracking
 * @returns Array of results with their request IDs
 */
export async function invokeBatchWithTracking<T = any>(
  operations: Array<{
    functionName: string;
    payload: any;
  }>,
  userId?: string
): Promise<
  Array<{
    functionName: string;
    data: T | null;
    error: any;
    requestId: string;
    duration: number;
  }>
> {
  const traceId = crypto.randomUUID();

  const results = await Promise.allSettled(
    operations.map(async (op) => {
      const result = await invokeWithTracking<T>(
        op.functionName,
        op.payload,
        userId,
        undefined,
        traceId
      );
      return { functionName: op.functionName, ...result };
    })
  );

  return results.map((result, index) => {
    if (result.status === 'fulfilled') {
      return result.value;
    } else {
      return {
        functionName: operations[index].functionName,
        data: null,
        error: { message: result.reason?.message || 'Unknown error' },
        requestId: 'unknown',
        duration: 0,
      };
    }
  });
}
