/**
 * Errors Module
 */

export class ApiError extends Error {
  constructor(
    message: string,
    public statusCode?: number,
    public code?: string
  ) {
    super(message);
    this.name = 'ApiError';
  }
}

export enum ErrorCode {
  NETWORK_ERROR = 'NETWORK_ERROR',
  AUTH_ERROR = 'AUTH_ERROR',
  VALIDATION_ERROR = 'VALIDATION_ERROR',
  SERVER_ERROR = 'SERVER_ERROR',
  NOT_FOUND = 'NOT_FOUND',
  TIMEOUT_ERROR = 'TIMEOUT_ERROR',
  SERVICE_UNAVAILABLE = 'SERVICE_UNAVAILABLE',
  PROVIDER_ERROR = 'PROVIDER_ERROR',
}

export const parseApiError = (error: any): { message: string; code: ErrorCode } => {
  if (error.response?.data?.detail) {
    return {
      message: error.response.data.detail,
      code: ErrorCode.SERVER_ERROR,
    };
  }
  if (error.code === 'ECONNABORTED') {
    return { message: 'Request timeout', code: ErrorCode.NETWORK_ERROR };
  }
  return { message: error.message || 'Unknown error', code: ErrorCode.SERVER_ERROR };
};

export const getUserFriendlyMessage = (error: any): string => {
  const parsed = parseApiError(error);
  return parsed.message;
};

export const retryWithBackoff = async <T>(
  fn: () => Promise<T>,
  options?: {
    maxRetries?: number;
    initialDelay?: number;
    retryableErrors?: ErrorCode[];
  }
): Promise<T> => {
  const maxRetries = options?.maxRetries ?? 3;
  const initialDelay = options?.initialDelay ?? 1000;
  const retryableErrors = options?.retryableErrors ?? [];

  let lastError: any;
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      lastError = error;
      const parsed = parseApiError(error);
      const isRetryable = retryableErrors.length === 0 || retryableErrors.includes(parsed.code);
      if (i < maxRetries - 1 && isRetryable) {
        await new Promise(resolve => setTimeout(resolve, initialDelay * Math.pow(2, i)));
      }
    }
  }
  throw lastError;
};
