
/**
 * Enhanced Error Handler with Retry Logic and Recovery
 */

import { toast } from '@/components/ui/use-toast';
import { errorLogger, ErrorSeverity } from './error-logger';
import { retryWithBackoff } from './performance';

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

export class NetworkError extends AppError {
  constructor(message: string = 'Network request failed') {
    super(message, 'NETWORK_ERROR', 0, 'medium');
    this.name = 'NetworkError';
  }
}

export class ValidationError extends AppError {
  constructor(message: string, public field?: string) {
    super(message, 'VALIDATION_ERROR', 400, 'low');
    this.name = 'ValidationError';
  }
}

export class AuthenticationError extends AppError {
  constructor(message: string = 'Authentication required') {
    super(message, 'AUTH_ERROR', 401, 'medium');
    this.name = 'AuthenticationError';
  }
}

export class AuthorizationError extends AppError {
  constructor(message: string = 'Not authorized to perform this action') {
    super(message, 'AUTHORIZATION_ERROR', 403, 'medium');
    this.name = 'AuthorizationError';
  }
}

export class NotFoundError extends AppError {
  constructor(message: string = 'Resource not found') {
    super(message, 'NOT_FOUND', 404, 'low');
    this.name = 'NotFoundError';
  }
}

// User-friendly error messages
const ERROR_MESSAGES: Record<string, string> = {
  NETWORK_ERROR: 'Unable to connect. Please check your internet connection and try again.',
  AUTH_ERROR: 'Please sign in to continue.',
  AUTHORIZATION_ERROR: 'You don\'t have permission to perform this action.',
  VALIDATION_ERROR: 'Please check your input and try again.',
  NOT_FOUND: 'The requested resource was not found.',
  SERVER_ERROR: 'An unexpected error occurred. Please try again later.',
};

export function handleError(
  error: unknown, 
  context?: string,
  showToast: boolean = true
) {
  let severity: ErrorSeverity = 'medium';
  let message = 'An unexpected error occurred. Please try again.';
  let code: string | undefined;

  if (error instanceof AppError) {
    severity = error.severity;
    message = ERROR_MESSAGES[error.code || ''] || error.message;
    code = error.code;
  } else if (error instanceof Error) {
    message = error.message;
  }

  // Log error
  errorLogger.log(error as Error, context, severity);

  // Show toast notification
  if (showToast) {
    toast({
      title: severity === 'critical' ? 'Critical Error' : 'Error',
      description: message,
      variant: 'destructive',
    });
  }

  return { message, code, severity };
}

export async function withErrorHandling<T>(
  fn: () => Promise<T>,
  context?: string,
  options: {
    showToast?: boolean;
    retry?: boolean;
    maxRetries?: number;
    fallback?: T;
  } = {}
): Promise<T | null> {
  const {
    showToast = true,
    retry = false,
    maxRetries = 3,
    fallback,
  } = options;

  try {
    if (retry) {
      return await retryWithBackoff(fn, maxRetries);
    }
    return await fn();
  } catch (error) {
    handleError(error, context, showToast);
    return fallback !== undefined ? fallback : null;
  }
}

/**
 * Fetch with automatic retry and error handling
 */
export async function fetchWithRetry<T>(
  url: string,
  options: RequestInit = {},
  maxRetries: number = 3
): Promise<T> {
  return retryWithBackoff(async () => {
    const response = await fetch(url, options);
    
    if (!response.ok) {
      if (response.status === 401) {
        throw new AuthenticationError();
      } else if (response.status === 403) {
        throw new AuthorizationError();
      } else if (response.status === 404) {
        throw new NotFoundError();
      } else if (response.status >= 500) {
        throw new AppError('Server error', 'SERVER_ERROR', response.status, 'high');
      } else {
        const errorData = await response.json().catch(() => ({}));
        throw new AppError(
          errorData.message || 'Request failed',
          'REQUEST_ERROR',
          response.status
        );
      }
    }
    
    return response.json();
  }, maxRetries);
}

/**
 * Safe async operation wrapper
 */
export async function safeAsync<T>(
  operation: () => Promise<T>,
  fallback: T,
  context?: string
): Promise<T> {
  try {
    return await operation();
  } catch (error) {
    errorLogger.log(error as Error, context, 'low');
    return fallback;
  }
}

/**
 * Validate and sanitize user input
 */
export function validateInput(
  value: any,
  rules: {
    required?: boolean;
    minLength?: number;
    maxLength?: number;
    pattern?: RegExp;
    custom?: (value: any) => boolean;
  },
  fieldName?: string
): { valid: boolean; error?: string } {
  if (rules.required && !value) {
    return {
      valid: false,
      error: `${fieldName || 'Field'} is required`,
    };
  }

  if (rules.minLength && value.length < rules.minLength) {
    return {
      valid: false,
      error: `${fieldName || 'Field'} must be at least ${rules.minLength} characters`,
    };
  }

  if (rules.maxLength && value.length > rules.maxLength) {
    return {
      valid: false,
      error: `${fieldName || 'Field'} must not exceed ${rules.maxLength} characters`,
    };
  }

  if (rules.pattern && !rules.pattern.test(value)) {
    return {
      valid: false,
      error: `${fieldName || 'Field'} format is invalid`,
    };
  }

  if (rules.custom && !rules.custom(value)) {
    return {
      valid: false,
      error: `${fieldName || 'Field'} validation failed`,
    };
  }

  return { valid: true };
}

/**
 * Global error recovery strategies
 */
export const errorRecovery = {
  // Reload current page
  reloadPage: () => {
    if (typeof window !== 'undefined') {
      window.location.reload();
    }
  },

  // Navigate to safe page
  navigateToSafe: (path: string = '/') => {
    if (typeof window !== 'undefined') {
      window.location.href = path;
    }
  },

  // Clear local storage and reload
  clearAndReload: () => {
    if (typeof window !== 'undefined') {
      localStorage.clear();
      sessionStorage.clear();
      window.location.reload();
    }
  },

  // Log out user
  logout: async () => {
    try {
      await fetch('/api/auth/signout', { method: 'POST' });
      if (typeof window !== 'undefined') {
        window.location.href = '/auth/signin';
      }
    } catch (error) {
      console.error('Logout failed:', error);
    }
  },
};
