/**
 * HTTP 请求工具
 * 基于 axios 的增强请求库，集成完整的错误处理、认证、重试等功能
 */

import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios'
import { ElMessage, ElMessageBox } from 'element-plus'
import { env } from '@/config/env'
import { handleHttpError, handleBusinessError } from './errorHandler'
import { loadingManager } from './loadingManager'

// 请求配置接口
interface RequestConfig extends AxiosRequestConfig {
  showLoading?: boolean
  showError?: boolean
  retry?: number
  retryDelay?: number
  skipAuth?: boolean
}

// 响应数据接口
interface ResponseData<T = any> {
  code: number
  message: string
  data: T
  success?: boolean
}

// Token 管理
class TokenManager {
  private tokenKey = 'access_token'
  private refreshTokenKey = 'refresh_token'
  private isRefreshing = false
  private failedQueue: Array<{
    resolve: (token: string) => void
    reject: (error: any) => void
  }> = []

  getToken(): string | null {
    return localStorage.getItem(this.tokenKey)
  }

  setToken(token: string): void {
    localStorage.setItem(this.tokenKey, token)
  }

  getRefreshToken(): string | null {
    return localStorage.getItem(this.refreshTokenKey)
  }

  setRefreshToken(token: string): void {
    localStorage.setItem(this.refreshTokenKey, token)
  }

  removeTokens(): void {
    localStorage.removeItem(this.tokenKey)
    localStorage.removeItem(this.refreshTokenKey)
  }

  async refreshAccessToken(): Promise<string> {
    const refreshToken = this.getRefreshToken()
    if (!refreshToken) {
      throw new Error('No refresh token available')
    }

    if (this.isRefreshing) {
      return new Promise((resolve, reject) => {
        this.failedQueue.push({ resolve, reject })
      })
    }

    this.isRefreshing = true

    try {
      const response = await axios.post('/api/v1/auth/refresh', {
        refresh_token: refreshToken
      })

      const { access_token } = response.data.data
      this.setToken(access_token)

      // 处理队列中的请求
      this.failedQueue.forEach(({ resolve }) => {
        resolve(access_token)
      })
      this.failedQueue = []

      return access_token
    } catch (error) {
      // 刷新失败，清除所有token并跳转到登录页
      this.removeTokens()
      this.failedQueue.forEach(({ reject }) => {
        reject(error)
      })
      this.failedQueue = []
      
      // 跳转到登录页
      window.location.href = '/login'
      throw error
    } finally {
      this.isRefreshing = false
    }
  }
}

// HTTP 客户端类
class HttpClient {
  private instance: AxiosInstance
  private tokenManager: TokenManager
  private requestQueue = new Map<string, AbortController>()

  constructor() {
    this.tokenManager = new TokenManager()
    this.instance = this.createInstance()
    this.setupInterceptors()
  }

  private createInstance(): AxiosInstance {
    // 确保超时时间至少5分钟（300秒），支持Dify等AI工作流的长时间处理
    // 开发环境可以设置更长时间用于调试
    const minTimeout = 300000 // 5分钟
    const timeout = env.isDevelopment 
      ? Math.max(minTimeout, 600000) // 开发环境：最长10分钟
      : Math.max(minTimeout, env.API_TIMEOUT) // 生产环境：至少5分钟
    
    return axios.create({
      // 开发环境不设置 baseURL，让请求走 Vite 代理，避免 CORS 问题
      baseURL: env.isDevelopment ? '' : env.API_BASE_URL,
      timeout: timeout,
      headers: {
        'Content-Type': 'application/json'
      }
    })
  }

  private setupInterceptors(): void {
    // 请求拦截器
    this.instance.interceptors.request.use(
      (config) => {
        const requestConfig = config as RequestConfig
        
        // 添加认证token
        if (!requestConfig.skipAuth) {
          const token = this.tokenManager.getToken()
          if (token) {
            config.headers!.Authorization = `Bearer ${token}`
          }
        }

        // 生成请求ID用于取消重复请求
        const requestId = this.generateRequestId(config)
        
        // 对于某些API（如AI判断），不取消重复请求，因为每次请求的答案可能不同
        const skipCancelApis = [
          '/api/v1/exams/judge-answer', 
          '/api/v1/exams/generate'
        ]
        const shouldSkipCancel = skipCancelApis.some(api => {
          if (api.includes('.*?')) {
            // 正则匹配
            return new RegExp(api).test(config.url || '')
          }
          return config.url?.includes(api)
        })
        
        // 取消相同的pending请求（跳过特定API）
        if (!shouldSkipCancel && this.requestQueue.has(requestId)) {
          this.requestQueue.get(requestId)!.abort()
        }

        // 创建新的AbortController（但不覆盖已有的signal，保留axios的timeout机制）
        if (!config.signal) {
          const abortController = new AbortController()
          config.signal = abortController.signal
          this.requestQueue.set(requestId, abortController)
        }

        // 显示加载状态
        if (requestConfig.showLoading) {
          loadingManager.start(requestId, {
            message: '请求中...',
            background: 'rgba(0, 0, 0, 0.3)'
          })
        }

        // 请求日志
        if (env.ENABLE_REQUEST_LOG) {
          console.log(`[HTTP Request] ${config.method?.toUpperCase()} ${config.url}`, {
            params: config.params,
            data: config.data
          })
        }

        return config
      },
      (error) => {
        return Promise.reject(error)
      }
    )

    // 响应拦截器
    this.instance.interceptors.response.use(
      (response: AxiosResponse<ResponseData>): any => {
        const config = response.config as RequestConfig
        const requestId = this.generateRequestId(config)
        
        // 清理请求队列
        this.requestQueue.delete(requestId)
        
        // 隐藏加载状态
        if (config.showLoading) {
          loadingManager.stop(requestId)
        }

        // 响应日志
        if (env.ENABLE_REQUEST_LOG) {
          console.log(`[HTTP Response] ${config.method?.toUpperCase()} ${config.url}`, {
            status: response.status,
            data: response.data
          })
        }

        const { code, message, success } = response.data
        
        // 调试：特殊处理exams/generate
        if (config.url?.includes('exams/generate')) {
          console.log('🔍 exams/generate响应详情:', {
            'response.status': response.status,
            'response.data': response.data,
            'typeof response.data': typeof response.data,
            'code': code,
            'message': message,
            'success': success
          })
        }

        // 业务成功
        if (code === 200 || success === true) {
          return response.data
        }

        // 业务错误
        const errorInfo = handleBusinessError(code, message, { response: response.data })
        if (config.showError !== false) {
          ElMessage.error(message || '请求失败')
        }
        
        return Promise.reject(errorInfo)
      },
      async (error: AxiosError) => {
        const config = error.config as RequestConfig
        const requestId = this.generateRequestId(config)
        
        // 清理请求队列
        this.requestQueue.delete(requestId)
        
        // 隐藏加载状态
        if (config?.showLoading) {
          loadingManager.stop(requestId)
        }

        // 处理取消的请求
        if (axios.isCancel(error)) {
          return Promise.reject(error)
        }

        // 处理401未授权错误
        if (error.response?.status === 401) {
          try {
            const newToken = await this.tokenManager.refreshAccessToken()
            // 重试原请求
            if (config) {
              config.headers!.Authorization = `Bearer ${newToken}`
              return this.instance.request(config)
            }
          } catch (refreshError) {
            // 刷新token失败，跳转到登录页
            ElMessageBox.alert('登录已过期，请重新登录', '提示', {
              confirmButtonText: '确定',
              callback: () => {
                window.location.href = '/login'
              }
            })
            return Promise.reject(refreshError)
          }
        }

        // 处理网络错误和其他HTTP错误
        const errorInfo = handleHttpError(error)
        
        // 显示错误信息
        if (config?.showError !== false) {
          if (error.response?.status === 500) {
            ElMessage.error('服务器内部错误，请稍后重试')
          } else if (error.code === 'ECONNABORTED') {
            ElMessage.error('请求超时，请稍后重试')
          } else if (!error.response) {
            ElMessage.error('网络连接失败，请检查网络设置')
          }
        }

        // 重试机制
        if (this.shouldRetry(error, config)) {
          return this.retryRequest(config)
        }

        return Promise.reject(errorInfo)
      }
    )
  }

  private generateRequestId(config: AxiosRequestConfig): string {
    const { method, url, params, data } = config
    return `${method}-${url}-${JSON.stringify(params)}-${JSON.stringify(data)}`
  }

  private shouldRetry(error: AxiosError, config?: RequestConfig): boolean {
    if (!config?.retry || config.retry <= 0) {
      return false
    }

    // 只重试网络错误和5xx服务器错误
    if (!error.response || (error.response.status >= 500 && error.response.status < 600)) {
      return true
    }

    return false
  }

  private async retryRequest(config: RequestConfig): Promise<any> {
    const retryCount = (config as any).__retryCount || 0
    const maxRetry = config.retry || 0
    
    if (retryCount >= maxRetry) {
      throw new Error('Max retry attempts exceeded')
    }

    // 增加重试计数
    ;(config as any).__retryCount = retryCount + 1

    // 等待一段时间后重试
    const delay = config.retryDelay || 1000 * Math.pow(2, retryCount) // 指数退避
    await new Promise(resolve => setTimeout(resolve, delay))

    console.log(`[HTTP Retry] Attempt ${retryCount + 1}/${maxRetry} for ${config.method?.toUpperCase()} ${config.url}`)

    return this.instance.request(config)
  }

  // 请求方法
  get<T = any>(url: string, config?: RequestConfig): Promise<ResponseData<T>> {
    return this.instance.get(url, config)
  }

  post<T = any>(url: string, data?: any, config?: RequestConfig): Promise<ResponseData<T>> {
    return this.instance.post(url, data, config)
  }

  put<T = any>(url: string, data?: any, config?: RequestConfig): Promise<ResponseData<T>> {
    return this.instance.put(url, data, config)
  }

  delete<T = any>(url: string, config?: RequestConfig): Promise<ResponseData<T>> {
    return this.instance.delete(url, config)
  }

  patch<T = any>(url: string, data?: any, config?: RequestConfig): Promise<ResponseData<T>> {
    return this.instance.patch(url, data, config)
  }

  // 上传文件
  upload<T = any>(url: string, file: File | FormData, config?: RequestConfig & {
    onUploadProgress?: (progress: number) => void
  }): Promise<ResponseData<T>> {
    const formData = file instanceof FormData ? file : new FormData()
    if (file instanceof File) {
      formData.append('file', file)
    }

    return this.instance.post(url, formData, {
      ...config,
      headers: {
        'Content-Type': 'multipart/form-data',
        ...config?.headers
      },
      onUploadProgress: (progressEvent) => {
        if (progressEvent.total && config?.onUploadProgress) {
          const progress = Math.round((progressEvent.loaded * 100) / progressEvent.total)
          config.onUploadProgress(progress)
        }
      }
    })
  }

  // 下载文件
  download(url: string, filename?: string, config?: RequestConfig): Promise<void> {
    return this.instance.get(url, {
      ...config,
      responseType: 'blob'
    }).then((response) => {
      const blob = new Blob([response.data])
      const downloadUrl = window.URL.createObjectURL(blob)
      const link = document.createElement('a')
      link.href = downloadUrl
      link.download = filename || 'download'
      document.body.appendChild(link)
      link.click()
      document.body.removeChild(link)
      window.URL.revokeObjectURL(downloadUrl)
    })
  }

  // 取消所有pending请求
  cancelAllRequests(): void {
    this.requestQueue.forEach((controller) => {
      controller.abort()
    })
    this.requestQueue.clear()
  }

  // 取消特定请求
  cancelRequest(url: string, method: string = 'GET'): void {
    const requestId = `${method}-${url}`
    const controller = this.requestQueue.get(requestId)
    if (controller) {
      controller.abort()
      this.requestQueue.delete(requestId)
    }
  }
}

// 创建HTTP客户端实例
export const http = new HttpClient()

// 导出便捷方法
export const { get, post, put, delete: del, patch, upload, download } = http

export default http
