import { supabase } from '@/integrations/supabase/client';

export class EdgeFunctionError extends Error {
  constructor(message, originalError = null, functionName = '') {
    super(message);
    this.name = 'EdgeFunctionError';
    this.originalError = originalError;
    this.functionName = functionName;
  }
}

export async function invokeEdgeFunction(functionName, options = {}, retries = 1) {
  const { body, headers = {}, ...rest } = options;
  let attempt = 0;

  if (!functionName || typeof functionName !== 'string') {
    const err = new EdgeFunctionError('Function name must be a non-empty string', null, functionName);
    console.error('[EdgeFunction] Invalid function name:', functionName);
    return { data: null, error: err };
  }

  while (attempt <= retries) {
    attempt++;
    const startTime = performance.now();

    try {
      const { data, error } = await supabase.functions.invoke(functionName, {
        body,
        headers: {
          ...(body ? { 'Content-Type': 'application/json' } : {}),
          ...headers,
        },
        ...rest
      });

      if (error) {
        console.warn(`[EdgeFunction] Error invoking ${functionName}:`, error);

        const isNetworkError = 
            error.name === 'FunctionsFetchError' || 
            error.name === 'FunctionsRelayError' || 
            (error instanceof TypeError && error.message === 'Failed to fetch');

        if (isNetworkError) {
           if (attempt <= retries) {
             console.warn(`[EdgeFunction] Network error invoking '${functionName}' on attempt ${attempt}, retrying...`);
             await new Promise(r => setTimeout(r, 1000 * attempt));
             continue;
           }

           throw new EdgeFunctionError(
             `Unable to reach function '${functionName}'. It may not be deployed, the name might be incorrect, or there are network/CORS issues.`,
             error,
             functionName
           );
        }

        let errorMessage = error.message || `Error invoking ${functionName}`;
        
        if (error.context && typeof error.context.json === 'function') {
            try {
                const errorBody = await error.context.json();
                if (errorBody) {
                    if (typeof errorBody.error === 'string') {
                        errorMessage = errorBody.error;
                    } else if (errorBody.message) {
                        errorMessage = errorBody.message;
                    } else {
                        errorMessage = JSON.stringify(errorBody);
                    }
                }
            } catch (e) {
                // ignore json parse error
            }
        }

        throw new EdgeFunctionError(errorMessage, error, functionName);
      }

      return { data, error: null };

    } catch (err) {
      const duration = Math.round(performance.now() - startTime);
      
      if (attempt > retries || (err instanceof EdgeFunctionError && !err.message.includes('Unable to reach'))) {
        console.error(`[EdgeFunction] Failed: ${functionName} (${duration}ms)`, err);
        
        if (err instanceof EdgeFunctionError) {
          return { data: null, error: err };
        }

        return { 
          data: null, 
          error: new EdgeFunctionError(
            err.message || `Unexpected error invoking ${functionName}`, 
            err, 
            functionName
          ) 
        };
      }
    }
  }
  
  return { data: null, error: new EdgeFunctionError('Max retries exceeded', null, functionName) };
}
