// API Client Service
import axios, { AxiosInstance, AxiosError, InternalAxiosRequestConfig, CancelTokenSource } from 'axios';
import toast from 'react-hot-toast';
import { env } from '@/config/env';
import { logger } from '@/utils/logger';
import { API_CONFIG, ERROR_MESSAGES } from '@/constants/config';

class ApiClient {
  private client: AxiosInstance;
  private cancelTokenSources = new Map<string, CancelTokenSource>();

  constructor() {
    this.client = axios.create({
      baseURL: env.VITE_API_BASE_URL,
      timeout: API_CONFIG.TIMEOUT,
      headers: {
        'Content-Type': 'application/json',
      },
    });

    this.setupInterceptors();
  }

  /**
   * Cancel a specific request by URL
   */
  cancelRequest(url: string): void {
    const source = this.cancelTokenSources.get(url);
    if (source) {
      source.cancel('Request cancelled');
      this.cancelTokenSources.delete(url);
    }
  }

  /**
   * Cancel all pending requests
   */
  cancelAllRequests(): void {
    this.cancelTokenSources.forEach((source) => {
      source.cancel('All requests cancelled');
    });
    this.cancelTokenSources.clear();
  }

  private setupInterceptors() {
    // Request interceptor
    this.client.interceptors.request.use(
      (config) => {
        const token = sessionStorage.getItem('auth_token');
        if (token) {
          config.headers.Authorization = `SOV-TOKEN ${token}`;
        }
        const source = axios.CancelToken.source();
        const url = config.url || '';
        this.cancelTokenSources.set(url, source);
        config.cancelToken = source.token;
        if (import.meta.env.DEV) {
          logger.logRequest(config.method || 'GET', url, config.data);
        }
        return config;
      },
      (error) => {
        logger.error('Request interceptor error', error);
        return Promise.reject(error);
      }
    );

    // Response interceptor
    this.client.interceptors.response.use(
      (response) => {
        const url = response.config.url || '';
        this.cancelTokenSources.delete(url);
        if (import.meta.env.DEV) {
          logger.logResponse(
            response.config.method || 'GET',
            url,
            response.status,
            response.data
          );
        }
        return response;
      },
      async (error: AxiosError) => {
        const url = error.config?.url || '';
        this.cancelTokenSources.delete(url);

        if (axios.isCancel(error)) {
          logger.debug('Request cancelled', { url });
          return Promise.reject(error);
        }

        if (error.response) {
          const status = error.response.status;
          const responseData = error.response.data as any;
          logger.error(`API Error ${status}`, error, {
            url: error.config?.url,
            method: error.config?.method,
            status,
            responseData,
          });

          switch (status) {
            case 401:
              sessionStorage.removeItem('auth_token');
              sessionStorage.removeItem('user');
              window.location.href = '/login';
              toast.error(ERROR_MESSAGES.UNAUTHORIZED);
              break;
            case 403:
              toast.error(ERROR_MESSAGES.FORBIDDEN);
              break;
            case 404:
              toast.error(ERROR_MESSAGES.NOT_FOUND);
              break;
            case 422:
              const validationErrors = responseData?.error?.details;
              if (validationErrors) {
                Object.values(validationErrors).forEach((msg: any) => {
                  toast.error(Array.isArray(msg) ? msg[0] : msg);
                });
              } else {
                toast.error(ERROR_MESSAGES.VALIDATION_ERROR);
              }
              break;
            case 500:
            case 502:
            case 503:
            case 504:
              toast.error(ERROR_MESSAGES.SERVER_ERROR);
              break;
            default:
              const message = responseData?.error?.message || ERROR_MESSAGES.UNEXPECTED_ERROR;
              toast.error(message);
          }
        } else if (error.request) {
          // Network error - API not reachable
          logger.error('Network error', error, { url: error.config?.url });
          // Transform network error to prevent generic toast and allow mock data handling
          const transformedError = new Error('API unavailable - using mock data');
          (transformedError as any).code = 'ERR_NETWORK';
          (transformedError as any).isNetworkError = true;
          return Promise.reject(transformedError);
        } else {
          logger.error('Request setup error', error);
          toast.error(ERROR_MESSAGES.UNEXPECTED_ERROR);
        }

        return Promise.reject(error);
      }
    );
  }

  get instance(): AxiosInstance {
    return this.client;
  }

  /**
   * GET request
   */
  async get<T>(url: string, config?: InternalAxiosRequestConfig): Promise<T> {
    const response = await this.client.get<T>(url, config);
    return response.data;
  }

  /**
   * POST request
   */
  async post<T>(url: string, data?: any, config?: InternalAxiosRequestConfig): Promise<T> {
    const response = await this.client.post<T>(url, data, config);
    return response.data;
  }

  /**
   * PUT request
   */
  async put<T>(url: string, data?: any, config?: InternalAxiosRequestConfig): Promise<T> {
    const response = await this.client.put<T>(url, data, config);
    return response.data;
  }

  /**
   * PATCH request
   */
  async patch<T>(url: string, data?: any, config?: InternalAxiosRequestConfig): Promise<T> {
    const response = await this.client.patch<T>(url, data, config);
    return response.data;
  }

  /**
   * DELETE request
   */
  async delete<T>(url: string, config?: InternalAxiosRequestConfig): Promise<T> {
    const response = await this.client.delete<T>(url, config);
    return response.data;
  }
}

export const apiClient = new ApiClient();
