/**
 * 请求封装
 * 统一处理请求和响应，支持模拟数据和真实接口切换
 */

import { API_CONFIG, ApiResponse } from './config'
import { handleHttpError } from '@/utils/errorHandler'
import { loadingManager } from '@/utils/loadingManager'

// 模拟延迟，使体验更真实
const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms))

// 扩展RequestInit接口以支持transformRequest
interface ExtendedRequestInit extends RequestInit {
  transformRequest?: Array<(data: any, headers?: any) => any>
}

class Request {
  /**
   * 通用请求方法
   * @param url 请求路径
   * @param options 请求选项
   * @param showLoading 是否显示加载状态
   * @returns Promise<ApiResponse<T>>
   */
  async request<T = any>(
    url: string, 
    options: ExtendedRequestInit = {}, 
    showLoading: boolean = false
  ): Promise<ApiResponse<T>> {
    const loadingKey = `api-${url}-${options.method || 'GET'}`
    
    if (showLoading) {
      loadingManager.start(loadingKey, {
        message: '请求中...',
        background: 'rgba(0, 0, 0, 0.3)'
      })
    }
    
    // 添加认证头
    const token = localStorage.getItem('access_token')
    if (token && !url.includes('/auth/login') && !url.includes('/auth/register')) {
      options.headers = {
        ...options.headers,
        'Authorization': `Bearer ${token}`
      }
    }
    
    try {
      // 如果使用模拟数据，直接返回模拟数据
      if (API_CONFIG.useMockData) {
        // 模拟网络延迟
        await delay(Math.random() * 500 + 200)

        // 动态导入对应的模拟数据
        const mockModule = await this.getMockData(url, options.method || 'GET')
        if (mockModule) {
          return {
            code: 200,
            message: '操作成功',
            data: mockModule
          }
        }

        // 如果没有模拟数据，抛出错误
        throw new Error(`未找到模拟数据: ${url}`)
      }

      // 真实 API 请求
      // 强制使用配置的基础URL，不使用代理
      let fullUrl = url.startsWith('http') ? url : `${API_CONFIG.baseURL}${url.startsWith('/') ? url : '/' + url}`
      
      // 生产环境安全检查：强制升级 HTTP 为 HTTPS
      if (fullUrl.startsWith('http://') && !fullUrl.includes('localhost') && !fullUrl.includes('127.0.0.1')) {
        fullUrl = fullUrl.replace('http://', 'https://')
        console.warn('[安全] 请求 URL 已自动升级为 HTTPS:', fullUrl)
      }
      
      const response = await fetch(fullUrl, {
        ...options,
        headers: {
          'Content-Type': 'application/json; charset=utf-8',
          'Accept': 'application/json; charset=utf-8',
          ...options.headers
        }
      })

      // 确保正确解码 UTF-8 响应
      const text = await response.text()
      let data: any
      try {
        data = JSON.parse(text)
      } catch {
        data = { detail: text || `请求失败: ${response.status}` }
      }

      if (!response.ok) {
        // 解析后端返回的错误详情
        const errorDetail = data?.detail || data?.message || `请求失败: ${response.status}`
        const error = new Error(typeof errorDetail === 'string' ? errorDetail : JSON.stringify(errorDetail)) as any
        error.status = response.status
        error.detail = errorDetail
        error.response = { data, status: response.status }
        throw error
      }

      return data
    } catch (error) {
      // 处理HTTP错误
      const errorInfo = handleHttpError(error)
      // 401 统一处理：清理本地状态并跳转登录
      try {
        const status = (errorInfo as any)?.status || (error as any)?.status
        if (status === 401) {
          console.warn('[Auth] Token过期或无效，正在清理认证状态', { url, status })
          localStorage.removeItem('access_token')
          localStorage.removeItem('refresh_token')
          localStorage.removeItem('current_user')
          // 避免死循环，仅在非登录页执行
          if (!location.pathname.startsWith('/login')) {
            console.info('[Auth] 重定向到登录页')
            location.href = '/login'
          }
        }
      } catch (authError) {
        // 认证处理过程中的异常不应影响主流程，但需要记录
        console.error('[Auth] 处理401错误时发生异常:', authError)
      }
      throw errorInfo
    } finally {
      if (showLoading) {
        loadingManager.stop(loadingKey)
      }
    }
  }

  /**
   * GET 请求
   */
  get<T = any>(url: string, options?: { params?: Record<string, any> }, showLoading?: boolean): Promise<ApiResponse<T>> {
    // 提取params参数
    const params = options?.params || {}
    
    // 过滤掉 undefined 和 null 的参数
    const filteredParams = Object.fromEntries(
      Object.entries(params).filter(([_, value]) => value !== undefined && value !== null)
    )
    
    const queryString = Object.keys(filteredParams).length > 0 
      ? '?' + new URLSearchParams(filteredParams as any).toString() 
      : ''
    return this.request<T>(url + queryString, { method: 'GET' }, showLoading)
  }

  /**
   * POST 请求
   */
  post<T = any>(url: string, data?: any, options?: ExtendedRequestInit, showLoading?: boolean): Promise<ApiResponse<T>> {
    let body = data
    let headers = { 'Content-Type': 'application/json', ...options?.headers }
    
    // 处理 transformRequest
    if (options?.transformRequest && Array.isArray(options.transformRequest)) {
      for (const transform of options.transformRequest) {
        if (typeof transform === 'function') {
          body = transform(data)
        }
      }
    } else if (data && typeof data === 'object' && !(data instanceof FormData) && !(data instanceof URLSearchParams)) {
      body = JSON.stringify(data)
    }
    
    return this.request<T>(url, {
      method: 'POST',
      body,
      ...options,
      headers
    }, showLoading)
  }

  /**
   * PUT 请求
   */
  put<T = any>(url: string, data?: any, showLoading?: boolean): Promise<ApiResponse<T>> {
    return this.request<T>(url, {
      method: 'PUT',
      body: JSON.stringify(data)
    }, showLoading)
  }

  /**
   * DELETE 请求
   */
  delete<T = any>(url: string, showLoading?: boolean): Promise<ApiResponse<T>> {
    return this.request<T>(url, { method: 'DELETE' }, showLoading)
  }

  /**
   * 文件上传请求
   */
  upload<T = any>(url: string, file: File, showLoading?: boolean): Promise<ApiResponse<T>> {
    const formData = new FormData()
    formData.append('file', file)
    
    return this.request<T>(url, {
      method: 'POST',
      body: formData,
      headers: {
        // 不设置 Content-Type，让浏览器自动设置（包含 boundary）
      }
    }, showLoading)
  }

  /**
   * 获取模拟数据
   * @private
   */
  private async getMockData(url: string, _method: string) {
    // 根据 URL 和 method 动态加载对应的模拟数据
    const mockPath = this.parseMockPath(url, _method)
    try {
      const module = await import(`./mock/${mockPath}.ts`)
      let mockData = module.default || module[_method.toLowerCase()]
      
      // 如果模拟数据是函数，则调用它
      if (typeof mockData === 'function') {
        // 解析查询参数
        const urlObj = new URL(url, 'http://localhost')
        const params: any = {}
        urlObj.searchParams.forEach((value, key) => {
          params[key] = value
        })
        mockData = mockData(params)
      }
      
      return mockData
    } catch (error) {
      console.warn(`未找到模拟数据: ${mockPath}`, error)
      return null
    }
  }

  /**
   * 解析模拟数据路径
   * @private
   */
  private parseMockPath(url: string, _method: string): string {
    // 移除查询参数
    const cleanUrl = url.split('?')[0]
    // 移除开头的斜杠
    const path = cleanUrl.startsWith('/') ? cleanUrl.slice(1) : cleanUrl
    // 将路径转换为模拟数据文件路径
    return path.replace(/\//g, '-')
  }
}

// 导出请求实例
export const request = new Request()

// 导出便捷方法
export const get = (url: string, params?: Record<string, any>, showLoading?: boolean) => 
  request.get(url, params ? { params } : undefined, showLoading)
  
export const post = (url: string, data?: any, showLoading?: boolean) => 
  request.post(url, data, undefined, showLoading)
  
export const put = (url: string, data?: any, showLoading?: boolean) => 
  request.put(url, data, showLoading)
  
export const del = (url: string, showLoading?: boolean) => 
  request.delete(url, showLoading)
  
export default request