export interface ApiResponse<T = unknown> {
  success: boolean;
  data?: T;
  message?: string;
  error?: string;
  details?: string;
}

export interface ApiError {
  message: string;
  status: number;
  details?: string;
  code?: string;
}

export class ApiClient {
  private static baseUrl = process.env.NEXT_PUBLIC_APP_URL || '';

  static async request<T = unknown>(
    endpoint: string, 
    options: RequestInit = {}
  ): Promise<ApiResponse<T>> {
    try {
      const url = endpoint.startsWith('http') ? endpoint : `${this.baseUrl}${endpoint}`;

      // Ensure headers exist and mark this request as toast-controlled to avoid duplicate global toasts
      const headers = new Headers({
        'Content-Type': 'application/json',
        ...(options.headers as Record<string, string> | undefined),
      });
      headers.set('x-toast-controlled', 'true');
      
      const response = await fetch(url, {
        headers,
        ...options,
      });

      const data = await response.json();

      if (!response.ok) {
        throw new ApiError(
          data.message || data.error || `HTTP ${response.status}: ${response.statusText}`,
          response.status,
          data.details,
          data.code
        );
      }

      return data as ApiResponse<T>;
    } catch (error) {
      if (error instanceof ApiError) {
        throw error;
      }
      
      // Handle network errors
      if (error instanceof TypeError && error.message.includes('fetch')) {
        throw new ApiError(
          'Network error: Please check your internet connection and try again.',
          0
        );
      }

      throw new ApiError(
        error instanceof Error ? error.message : 'An unexpected error occurred',
        500
      );
    }
  }

  static async get<T = unknown>(endpoint: string): Promise<ApiResponse<T>> {
    return this.request<T>(endpoint, { method: 'GET' });
  }

  static async post<T = unknown>(endpoint: string, data?: unknown): Promise<ApiResponse<T>> {
    return this.request<T>(endpoint, {
      method: 'POST',
      body: data ? JSON.stringify(data) : undefined,
    });
  }

  static async put<T = unknown>(endpoint: string, data?: unknown): Promise<ApiResponse<T>> {
    return this.request<T>(endpoint, {
      method: 'PUT',
      body: data ? JSON.stringify(data) : undefined,
    });
  }

  static async delete<T = unknown>(endpoint: string): Promise<ApiResponse<T>> {
    return this.request<T>(endpoint, { method: 'DELETE' });
  }
}

export class ApiError extends Error {
  public status: number;
  public details?: string;
  public code?: string;

  constructor(message: string, status: number, details?: string, code?: string) {
    super(message);
    this.name = 'ApiError';
    this.status = status;
    this.details = details;
    this.code = code;
  }

  public isNetworkError(): boolean {
    return this.status === 0;
  }

  public isServerError(): boolean {
    return this.status >= 500;
  }

  public isClientError(): boolean {
    return this.status >= 400 && this.status < 500;
  }

  public isUnauthorized(): boolean {
    return this.status === 401;
  }

  public isForbidden(): boolean {
    return this.status === 403;
  }

  public isNotFound(): boolean {
    return this.status === 404;
  }

  public getDisplayMessage(): string {
    // Provide user-friendly error messages
    if (this.isNetworkError()) {
      return 'Unable to connect to the server. Please check your internet connection.';
    }
    
    if (this.isUnauthorized()) {
      return 'Please log in to continue.';
    }
    
    if (this.isForbidden()) {
      return 'You do not have permission to perform this action.';
    }
    
    if (this.isNotFound()) {
      return 'The requested resource was not found.';
    }
    
    if (this.isServerError()) {
      return 'A server error occurred. Please try again later.';
    }

    return this.message;
  }
}