import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios';
import { ApiResponse } from '@goodgo/types';

/**
 * EN: Configuration interface for HTTP client setup
 * VI: Interface cấu hình cho việc thiết lập HTTP client
 */
export interface HttpClientConfig extends AxiosRequestConfig {
  /** EN: Base URL for all API requests / VI: Base URL cho tất cả API requests */
  baseURL: string;
  /** EN: Request timeout in milliseconds / VI: Timeout request tính bằng milliseconds */
  timeout?: number;
  /** EN: Default headers for all requests / VI: Headers mặc định cho tất cả requests */
  headers?: Record<string, string>;
}

/**
 * EN: HTTP client wrapper around Axios with authentication and error handling
 * VI: HTTP client wrapper xung quanh Axios với authentication và xử lý lỗi
 */
export class HttpClient {
  /** EN: Axios instance for making HTTP requests / VI: Axios instance để thực hiện HTTP requests */
  private client: AxiosInstance;

  /**
   * EN: Initialize HTTP client with configuration
   * VI: Khởi tạo HTTP client với cấu hình
   *
   * @param config - HTTP client configuration / Cấu hình HTTP client
   */
  constructor(config: HttpClientConfig) {
    // EN: Create Axios instance with base configuration
    // VI: Tạo Axios instance với cấu hình cơ bản
    this.client = axios.create({
      baseURL: config.baseURL,
      timeout: config.timeout || 30000,
      headers: {
        'Content-Type': 'application/json',
        ...config.headers,
      },
    });

    // EN: Setup request/response interceptors
    // VI: Thiết lập interceptors cho request/response
    this.setupInterceptors();
  }

  /**
   * EN: Setup Axios interceptors for authentication and error handling
   * VI: Thiết lập Axios interceptors cho authentication và xử lý lỗi
   */
  private setupInterceptors() {
    // EN: Request interceptor to add authentication token
    // VI: Request interceptor để thêm authentication token
    this.client.interceptors.request.use(
      (config) => {
        // EN: Add auth token if available in localStorage
        // VI: Thêm auth token nếu có trong localStorage
        const token = this.getAuthToken();
        if (token) {
          config.headers.Authorization = `Bearer ${token}`;
        }
        return config;
      },
      (error) => Promise.reject(error)
    );

    // EN: Response interceptor for error handling
    // VI: Response interceptor để xử lý lỗi
    this.client.interceptors.response.use(
      (response: AxiosResponse<ApiResponse>) => {
        return response;
      },
      (error: AxiosError<ApiResponse>) => {
        // EN: Handle common HTTP errors
        // VI: Xử lý các lỗi HTTP phổ biến
        if (error.response?.status === 401) {
          // EN: Handle unauthorized - clear tokens and redirect to login
          // VI: Xử lý unauthorized - xóa tokens và chuyển hướng đến login
          this.clearAuthToken();
        }
        return Promise.reject(error);
      }
    );
  }

  /**
   * EN: Get authentication token from localStorage
   * VI: Lấy authentication token từ localStorage
   *
   * @returns Access token or null if not found / Access token hoặc null nếu không tìm thấy
   */
  private getAuthToken(): string | null {
    // EN: Check if running in browser environment
    // VI: Kiểm tra có đang chạy trong môi trường browser không
    if (typeof window !== 'undefined') {
      return localStorage.getItem('accessToken');
    }
    return null;
  }

  /**
   * EN: Clear authentication tokens from localStorage
   * VI: Xóa authentication tokens khỏi localStorage
   */
  private clearAuthToken(): void {
    // EN: Remove both access and refresh tokens
    // VI: Xóa cả access và refresh tokens
    if (typeof window !== 'undefined') {
      localStorage.removeItem('accessToken');
      localStorage.removeItem('refreshToken');
    }
  }

  /**
   * EN: Make GET request to API endpoint
   * VI: Thực hiện GET request tới API endpoint
   *
   * @param url - API endpoint URL / URL endpoint API
   * @param config - Additional Axios config / Cấu hình Axios bổ sung
   * @returns API response data / Dữ liệu phản hồi API
   */
  async get<T = any>(url: string, config?: AxiosRequestConfig): Promise<ApiResponse<T>> {
    const response = await this.client.get<ApiResponse<T>>(url, config);
    return response.data;
  }

  /**
   * EN: Make POST request to API endpoint
   * VI: Thực hiện POST request tới API endpoint
   *
   * @param url - API endpoint URL / URL endpoint API
   * @param data - Request payload / Payload request
   * @param config - Additional Axios config / Cấu hình Axios bổ sung
   * @returns API response data / Dữ liệu phản hồi API
   */
  async post<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<ApiResponse<T>> {
    const response = await this.client.post<ApiResponse<T>>(url, data, config);
    return response.data;
  }

  /**
   * EN: Make PUT request to API endpoint
   * VI: Thực hiện PUT request tới API endpoint
   *
   * @param url - API endpoint URL / URL endpoint API
   * @param data - Request payload / Payload request
   * @param config - Additional Axios config / Cấu hình Axios bổ sung
   * @returns API response data / Dữ liệu phản hồi API
   */
  async put<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<ApiResponse<T>> {
    const response = await this.client.put<ApiResponse<T>>(url, data, config);
    return response.data;
  }

  /**
   * EN: Make PATCH request to API endpoint
   * VI: Thực hiện PATCH request tới API endpoint
   *
   * @param url - API endpoint URL / URL endpoint API
   * @param data - Request payload / Payload request
   * @param config - Additional Axios config / Cấu hình Axios bổ sung
   * @returns API response data / Dữ liệu phản hồi API
   */
  async patch<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<ApiResponse<T>> {
    const response = await this.client.patch<ApiResponse<T>>(url, data, config);
    return response.data;
  }

  /**
   * EN: Make DELETE request to API endpoint
   * VI: Thực hiện DELETE request tới API endpoint
   *
   * @param url - API endpoint URL / URL endpoint API
   * @param config - Additional Axios config / Cấu hình Axios bổ sung
   * @returns API response data / Dữ liệu phản hồi API
   */
  async delete<T = any>(url: string, config?: AxiosRequestConfig): Promise<ApiResponse<T>> {
    const response = await this.client.delete<ApiResponse<T>>(url, config);
    return response.data;
  }

  /**
   * EN: Set authentication token in localStorage
   * VI: Đặt authentication token trong localStorage
   *
   * @param token - JWT access token / JWT access token
   */
  setAuthToken(token: string): void {
    // EN: Store token in browser localStorage
    // VI: Lưu token trong localStorage của browser
    if (typeof window !== 'undefined') {
      localStorage.setItem('accessToken', token);
    }
  }

  /**
   * EN: Remove authentication token from localStorage
   * VI: Xóa authentication token khỏi localStorage
   */
  removeAuthToken(): void {
    this.clearAuthToken();
  }
}

/**
 * EN: Factory function to create HttpClient instance
 * VI: Hàm factory để tạo HttpClient instance
 *
 * @param config - HTTP client configuration / Cấu hình HTTP client
 * @returns HttpClient instance / Instance HttpClient
 */
export const createHttpClient = (config: HttpClientConfig): HttpClient => {
  return new HttpClient(config);
};

// EN: Default export for the HttpClient class
// VI: Export default cho HttpClient class
export default HttpClient;
