import { message } from 'antd';
import { CacheUtils } from './cache';
import { apiDebounce } from './apiDebounce';

interface RequestConfig extends RequestInit {
  params?: Record<string, any>;
  useCache?: boolean;
  cacheTime?: number;
  debounce?: boolean;
}

interface ApiResponse<T = any> {
  data: T;
  code: number;
  message: string;
}

const BASE_URL = '/api';
const DEFAULT_TIMEOUT = 30000;

class ApiClient {
  private baseURL: string;
  private timeout: number;
  private pendingRequests: Map<string, Promise<any>>;

  constructor(baseURL: string = BASE_URL, timeout: number = DEFAULT_TIMEOUT) {
    this.baseURL = baseURL;
    this.timeout = timeout;
    this.pendingRequests = new Map();
  }

  private buildURL(url: string, params?: Record<string, any>): string {
    const fullURL = url.startsWith('http') ? url : `${this.baseURL}${url}`;
    if (!params) return fullURL;
    
    const searchParams = new URLSearchParams();
    Object.entries(params).forEach(([key, value]) => {
      if (value !== undefined && value !== null) {
        searchParams.append(key, String(value));
      }
    });
    
    const queryString = searchParams.toString();
    return queryString ? `${fullURL}?${queryString}` : fullURL;
  }

  private getCacheKey(url: string, options?: RequestConfig): string {
    return `${options?.method || 'GET'}:${url}:${JSON.stringify(options?.body || '')}`;
  }

  private async request<T>(
    url: string,
    options: RequestConfig = {}
  ): Promise<ApiResponse<T>> {
    const {
      params,
      useCache = false,
      cacheTime = 5 * 60 * 1000,
      debounce = false,
      ...fetchOptions
    } = options;

    const fullURL = this.buildURL(url, params);
    const cacheKey = this.getCacheKey(fullURL, fetchOptions);

    if (useCache) {
      const cachedData = CacheUtils.get<ApiResponse<T>>(cacheKey);
      if (cachedData) {
        return cachedData;
      }
    }

    if (debounce && this.pendingRequests.has(cacheKey)) {
      return this.pendingRequests.get(cacheKey)!;
    }

    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), this.timeout);

    const defaultHeaders: HeadersInit = {
      'Content-Type': 'application/json',
    };

    const token = localStorage.getItem('token');
    if (token) {
      defaultHeaders['Authorization'] = `Bearer ${token}`;
    }

    const requestPromise = fetch(fullURL, {
      ...fetchOptions,
      headers: {
        ...defaultHeaders,
        ...fetchOptions.headers,
      },
      signal: controller.signal,
    })
      .then(async (response) => {
        clearTimeout(timeoutId);
        
        if (!response.ok) {
          const errorData = await response.json().catch(() => ({}));
          throw new Error(errorData.message || `HTTP Error: ${response.status}`);
        }
        
        const result: ApiResponse<T> = await response.json();
        
        if (result.code !== 0 && result.code !== 200) {
          throw new Error(result.message || '请求失败');
        }
        
        if (useCache) {
          CacheUtils.set(cacheKey, result, cacheTime);
        }
        
        return result;
      })
      .catch((error) => {
        clearTimeout(timeoutId);
        
        if (error.name === 'AbortError') {
          throw new Error('请求超时');
        }
        
        if (error.message.includes('401')) {
          localStorage.removeItem('token');
          window.location.href = '/login';
        }
        
        message.error(error.message || '网络错误');
        throw error;
      })
      .finally(() => {
        this.pendingRequests.delete(cacheKey);
      });

    if (debounce) {
      this.pendingRequests.set(cacheKey, requestPromise);
    }

    return requestPromise;
  }

  async get<T>(url: string, params?: Record<string, any>, config?: RequestConfig): Promise<ApiResponse<T>> {
    return this.request<T>(url, { ...config, method: 'GET', params });
  }

  async post<T>(url: string, data?: any, config?: RequestConfig): Promise<ApiResponse<T>> {
    return this.request<T>(url, {
      ...config,
      method: 'POST',
      body: JSON.stringify(data),
    });
  }

  async put<T>(url: string, data?: any, config?: RequestConfig): Promise<ApiResponse<T>> {
    return this.request<T>(url, {
      ...config,
      method: 'PUT',
      body: JSON.stringify(data),
    });
  }

  async delete<T>(url: string, config?: RequestConfig): Promise<ApiResponse<T>> {
    return this.request<T>(url, { ...config, method: 'DELETE' });
  }

  async upload<T>(url: string, file: File, config?: RequestConfig): Promise<ApiResponse<T>> {
    const formData = new FormData();
    formData.append('file', file);
    
    return this.request<T>(url, {
      ...config,
      method: 'POST',
      body: formData,
      headers: {
        ...config?.headers,
      },
    });
  }

  clearCache(): void {
    CacheUtils.clear();
  }

  cancelPendingRequests(): void {
    this.pendingRequests.clear();
  }
}

export const api = new ApiClient();

export const request = {
  get: <T>(url: string, params?: Record<string, any>, config?: RequestConfig) => 
    api.get<T>(url, params, { ...config, useCache: true }),
  
  post: <T>(url: string, data?: any, config?: RequestConfig) => 
    api.post<T>(url, data, { ...config, debounce: true }),
  
  put: <T>(url: string, data?: any, config?: RequestConfig) => 
    api.put<T>(url, data, config),
  
  delete: <T>(url: string, config?: RequestConfig) => 
    api.delete<T>(url, config),
  
  upload: <T>(url: string, file: File, config?: RequestConfig) => 
    api.upload<T>(url, file, config),
};

export default api;
