import Taro from '@tarojs/taro'

// ==================== 类型定义 ====================

/** 后端统一响应结构 */
export interface ResponseStructure<T = any> {
  success: boolean
  msg?: string
  showType?: number // 0-2: Toast 提示; 3-5: Modal 通知; 99: 静默处理
  description?: string
  placement?: string
  data?: T
}

/** 请求配置（兼容 Taro.request.Option） */
export interface RequestConfig {
  url: string
  method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'OPTIONS' | 'HEAD' | 'TRACE' | 'CONNECT'
  data?: any
  header?: Record<string, any>
  timeout?: number
  dataType?: 'json' | 'text' | 'base64' | 'arraybuffer'
  responseType?: 'text' | 'arraybuffer'
}

// ==================== 配置常量 ====================
/** 请求超时时间 */
const REQUEST_TIMEOUT = 10000
/** 登录页面 */
const LOGIN_PATH = '/pages/login/index'
/** API 基础地址 */
const BASE_URL = 'http://localhost:8000'

/**
 * 解析请求 URL，自动拼接 BASE_URL
 */
function resolveUrl(url: string): string {
  // 已经是完整 URL
  if (/^https?:\/\//i.test(url)) {
    return url
  }
  return BASE_URL + url
}

// ==================== 错误处理 ====================

/**
 * 处理网络错误（HTTP 状态码错误）
 */
async function handleNetworkError(statusCode?: number): Promise<void> {
  if (!statusCode) {
    Taro.showToast({ title: '无法连接到服务器！', icon: 'none', duration: 2000 })
    return
  }

  // 401 未授权
  if (statusCode === 401) {
    Taro.showToast({ title: '您未登录，或者登录已经超时，请先登录！', icon: 'none', duration: 2500 })

    // 清除本地认证信息
    Taro.removeStorageSync('token')
    Taro.removeStorageSync('refresh_token')
    Taro.removeStorageSync('auth-storage')

    // 避免在登录页重复跳转
    const pages = Taro.getCurrentPages()
    const currentRoute = pages.length > 0 ? pages[pages.length - 1].route : ''
    if (currentRoute !== LOGIN_PATH.replace(/^\//, '')) {
      Taro.redirectTo({ url: LOGIN_PATH })
    }
    return
  }

  const errorMessages: Record<number, string> = {
    302: '接口重定向了！',
    400: '参数不正确！',
    403: '您没有权限操作！',
    404: '请求错误，未找到该资源！',
    408: '请求超时！',
    409: '系统已存在相同数据！',
    500: '服务器内部错误！',
    501: '服务未实现！',
    502: '网关错误！',
    503: '服务不可用！',
    504: '服务暂时无法访问，请稍后再试！',
    505: 'HTTP 版本不受支持！',
  }

  const message = errorMessages[statusCode] || `连接错误 (状态码: ${statusCode})`
  Taro.showToast({ title: message, icon: 'none', duration: 2500 })
}

/**
 * 处理业务错误（接口返回的业务逻辑错误）
 */
async function handleBusinessError(data: ResponseStructure): Promise<void> {
  const { msg = '', showType = 0, description = '' } = data

  switch (showType) {
    case 99: // 静默处理
      break
    case 0: // Toast 成功
      if (msg) Taro.showToast({ title: msg, icon: 'success', duration: 2000 })
      break
    case 1: // Toast 警告
      if (msg) Taro.showToast({ title: msg, icon: 'none', duration: 2500 })
      break
    case 2: // Toast 错误
      if (msg) Taro.showToast({ title: msg, icon: 'error', duration: 2500 })
      break
    case 3: // Modal 成功
      if (msg) Taro.showModal({ title: msg, content: description || '', showCancel: false })
      break
    case 4: // Modal 警告
      if (msg) Taro.showModal({ title: msg, content: description || '', showCancel: false })
      break
    case 5: // Modal 错误
      if (msg) Taro.showModal({ title: msg, content: description || '', showCancel: false })
      break
    default:
      if (msg) Taro.showToast({ title: msg, icon: 'none', duration: 2500 })
  }
}

// ==================== 核心请求函数 ====================

/**
 * 创建请求
 * @param config - 请求配置
 * @returns Promise<ResponseStructure<Data>>
 */
export async function createRequest<Data = any>(
  config: RequestConfig,
): Promise<ResponseStructure<Data>> {

  // 2. 构建 headers
  const header: Record<string, any> = { ...(config.header || {}) }

  // 附加国际化语言
  try {
    const language = Taro.getStorageSync('i18nextLng')
    if (language) {
      header['User-Language'] = language
    }
  } catch {
    // storage 读取失败时忽略
  }

  // 附加 Token（排除登录接口）
  try {
    const token = Taro.getStorageSync('token')
    if (token) {
      header['Authorization'] = `Bearer ${token}`
    }
  } catch {
    // storage 读取失败时忽略
  }

  try {
    // 4. 发起请求
    const task = Taro.request<ResponseStructure<Data>>({
      url: resolveUrl(config.url),
      method: config.method || 'GET',
      data: config.data,
      header,
      timeout: config.timeout || REQUEST_TIMEOUT,
      dataType: config.dataType || 'json',
      responseType: config.responseType,
    })

    const response = await task

    const body = response.data as ResponseStructure<Data>

    if (body?.success) {
      return body
    }

    // 8. 业务失败：显示错误提示并 reject
    if (body) {
      await handleBusinessError(body)
    }

    return Promise.reject(body)
  } catch (err: any) {

    // 请求被取消（去重或手动取消）
    if (err?.errMsg?.includes('abort') || err?.errMsg?.includes('cancel')) {
      console.warn('请求已取消:', err.errMsg)
      return Promise.reject(err)
    }

    // 有 HTTP 状态码但非 2xx
    if (err?.statusCode) {
      await handleNetworkError(err.statusCode)
      return Promise.reject(err)
    }

    // 网络超时
    if (err?.errMsg?.includes('timeout')) {
      Taro.showToast({ title: '请求超时，请稍后重试！', icon: 'none', duration: 2500 })
      return Promise.reject(err)
    }

    // 网络连接失败
    if (err?.errMsg?.includes('fail') || err?.message?.includes('Network Error')) {
      Taro.showToast({ title: '网络连接失败，请检查网络！', icon: 'none', duration: 2500 })
      return Promise.reject(err)
    }

    // 其他未知错误
    Taro.showToast({
      title: `网络错误: ${err?.errMsg || err?.message || '未知错误'}`,
      icon: 'none',
      duration: 2500,
    })
    return Promise.reject(err)
  }
}

export default createRequest
