import { useTokenStore } from '@/store/token'

interface RequestOptions {
  url: string
  method?: 'GET' | 'POST' | 'PUT' | 'DELETE'
  data?: any
  params?: any
  headers?: Record<string, string>
  loading?: boolean
  loadingText?: string
  unique?: boolean
}

class Request {
  private baseURL: string
  private pendingRequests: Map<string, AbortController>

  constructor() {
    this.baseURL = import.meta.env.VITE_API_BASE_URL || ''
    this.pendingRequests = new Map()
  }

  private generateRequestKey(config: RequestOptions): string {
    return `${config.method}&${config.url}&${JSON.stringify(config.data)}&${JSON.stringify(config.params)}`
  }

  private async request<T>(options: RequestOptions): Promise<T> {
    const tokenStore = useTokenStore()
    const requestKey = this.generateRequestKey(options)
    // 防止重复请求
    if (options.unique && this.pendingRequests.has(requestKey)) {
      this.pendingRequests.get(requestKey)?.abort()
      this.pendingRequests.delete(requestKey)
    }

    const controller = new AbortController()
    this.pendingRequests.set(requestKey, controller)

    // 显示 loading
    if (options.loading) {
      uni.showLoading({
        title: options.loadingText || '加载中...',
        mask: true,
      })
    }

    try {
      // 处理GET请求的params参数
      let url = this.baseURL + options.url
      if (options.method === 'GET' && options.params) {
        const params = new URLSearchParams()
        for (const [key, value] of Object.entries(options.params)) {
          if (value !== undefined && value !== null) {
            params.append(key, String(value))
          }
        }
        const paramsString = params.toString()
        if (paramsString) {
          url += (url.includes('?') ? '&' : '?') + paramsString
        }
      }
      
      const response = await new Promise<UniApp.RequestSuccessCallbackResult>((resolve, reject) => {
        uni.request({
          url,
          method: options.method || 'GET',
          data: options.data,
          dataType: 'json',
          header: {
            'Content-Type': 'application/json',
            'Authorization': tokenStore.validToken ? `Bearer ${tokenStore.validToken}` : '',
            ...options.headers,
          },
          success: resolve,
          fail: reject,
        })
      })

      // 关闭 loading
      if (options.loading) {
        uni.hideLoading()
      }

      this.pendingRequests.delete(requestKey)

      const data = response.data as any
      // 根据后端接口结构调整
      if (data.code === 200 || data.success) {
        return data.data || data
      }
      else {
        // 统一错误处理
        this.handleError(data.code, data.msg)
        throw new Error(data.msg || '请求失败')
      }
    }
    catch (error) {
      if (options.loading) {
        uni.hideLoading()
      }
      this.pendingRequests.delete(requestKey)
      this.handleNetworkError(error)
      throw error
    }
  }

  private handleError(code: number, msg: string) {
    const errorMessages: { [key: number]: string } = {
      401: '未授权，请重新登录',
      403: '拒绝访问',
      404: '请求的资源不存在',
      500: '服务器内部错误',
      502: '网关错误',
      503: '服务不可用',
    }

    const errorMessage = msg || errorMessages[code] || '未知错误'

    uni.showToast({
      title: errorMessage,
      icon: 'none',
      duration: 3000,
    })

    //  token 过期处理
    if (code === 401) {
      const tokenStore = useTokenStore()
      tokenStore.logout()
      uni.navigateTo({
        url: '/pages-fg/login/login',
      })
    }
  }

  private handleNetworkError(error: any) {
    console.error('Network Error:', error)
    uni.showToast({
      title: '网络连接失败，请检查网络设置',
      icon: 'none',
      duration: 3000,
    })
  }

  get<T>(url: string, params?: any, options: Partial<RequestOptions> = {}) {
    return this.request<T>({
      url,
      method: 'GET',
      params,
      ...options,
    })
  }

  post<T>(url: string, data?: any, options: Partial<RequestOptions> = {}) {
    return this.request<T>({
      url,
      method: 'POST',
      data,
      ...options,
    })
  }

  put<T>(url: string, data?: any, options: Partial<RequestOptions> = {}) {
    return this.request<T>({
      url,
      method: 'PUT',
      data,
      ...options,
    })
  }

  delete<T>(url: string, data?: any, options: Partial<RequestOptions> = {}) {
    return this.request<T>({
      url,
      method: 'DELETE',
      data,
      ...options,
    })
  }
}

export const http = new Request()
