import axios from 'axios'
import Cookie from 'js-cookie'
import CryptoJS from 'crypto-js'
import Vue from 'vue'
import { GanShenMe } from '../utils/util'

import { ACCESS_TOKEN, SYSTEM_VERSION, V4_ACCESS_TOKEN, V4_SESSION_KEY } from '@vue2-client/store/mutation-types'
import notification from 'ant-design-vue/es/notification'
import errorCode from '@vue2-client/utils/errorCode'
import qs from 'qs'
import { logout, V4RefreshToken } from '@vue2-client/services/user'
import { LOGIN, SEARCH, V4_LOGIN } from '@vue2-client/services/apiService'
import { setV4AccessToken } from '@vue2-client/utils/login'
import EncryptUtil from '@vue2-client/utils/EncryptUtil'
// 引入请求去重模块
import {
  DEDUPE_STRATEGY,
  generateRequestKey,
  hasPendingRequest,
  addPendingRequest,
  handleDuplicateRequest,
  resolvePendingRequest,
  rejectPendingRequest,
  clearPendingRequests as clearAllPendingRequests,
  shouldEnableDedupe,
  getDedupeStrategy
} from '@vue2-client/utils/requestDedupe'

// 是否显示重新登录
let isReloginShow

/**
 * 业务 code 500 及其他非 200（不含 601）时是否显示默认错误提示（notification）
 * @param {import('axios').AxiosRequestConfig} [config]
 * @returns {boolean}
 */
function shouldShowErrorMessage(config) {
  return config?.showErrorMessage !== false
}

/**
 * 清空所有 pending 请求
 * @description 页面切换或需要取消所有请求时调用
 */
export function clearPendingRequests() {
  clearAllPendingRequests()
}

// 导出去重策略常量，方便外部使用
export { DEDUPE_STRATEGY }

axios.defaults.timeout = 50000
axios.defaults.withCredentials = true
// 如果是microapp
if (window.__MICRO_APP_ENVIRONMENT__) {
  const data = window.microApp.getData() // 获取主应用下发的data数据
  // 修改baseurl为主应用地址
  if (data.origin) {
    axios.defaults.baseURL = data.origin
  }
}
// 认证类型
const AUTH_TYPE = {
  BEARER: 'Bearer',
  BASIC: 'basic',
  AUTH1: 'auth1',
  AUTH2: 'auth2'
}

// http method
const METHOD = {
  GET: 'get',
  POST: 'post',
  PUT: 'put',
  DELETE: 'delete'
}
/**
 * axios请求
 * @param url 请求地址
 * @param method {METHOD} http method
 * @param params 请求参数
 * @param config 支持 signal 参数用于取消请求
 * @returns {Promise<AxiosResponse<T>>}
 */
async function request(url, method, params, config) {
  // 提取 signal 参数
  const { signal, ...restConfig } = config || {}

  switch (method) {
    case METHOD.GET:
      return axios.get(url, { params, ...restConfig, signal })
    case METHOD.POST:
      return axios.post(url, params, { ...restConfig, signal })
    case METHOD.PUT:
      return axios.put(url, params, { ...restConfig, signal })
    case METHOD.DELETE:
      return axios.delete(url, { params, ...restConfig, signal })
    default:
      return axios.get(url, { params, ...restConfig, signal })
  }
}

/**
 * 设置认证信息
 * @param auth {Object}
 * @param authType {AUTH_TYPE} 认证类型，默认：{AUTH_TYPE.BEARER}
 */
function setAuthorization(auth, authType = AUTH_TYPE.BEARER) {
  switch (authType) {
    case AUTH_TYPE.BEARER:
      localStorage.setItem(V4_ACCESS_TOKEN, 'Bearer ' + auth.token)
      Cookie.set(V4_ACCESS_TOKEN, 'Bearer ' + auth.token, { expires: auth.expireAt })
      break
    case AUTH_TYPE.BASIC:
    case AUTH_TYPE.AUTH1:
    case AUTH_TYPE.AUTH2:
    default:
      break
  }
}

/**
 * 设置系统版本
 * @param value 系统版本
 */
export function setSystemVersion(value) {
  Cookie.set(SYSTEM_VERSION, value)
}

/**
 * 获取系统版本
 */
export function getSystemVersion() {
  return Cookie.get(SYSTEM_VERSION) || 'V4'
}

/**
 * 移出认证信息
 * @param authType {AUTH_TYPE} 认证类型
 */
function removeAuthorization(authType = AUTH_TYPE.BEARER) {
  switch (authType) {
    case AUTH_TYPE.BEARER:
      Cookie.remove(V4_ACCESS_TOKEN)
      localStorage.removeItem(V4_ACCESS_TOKEN)
      localStorage.removeItem(V4_SESSION_KEY)
      break
    case AUTH_TYPE.BASIC:
    case AUTH_TYPE.AUTH1:
    case AUTH_TYPE.AUTH2:
    default:
      break
  }
}

/**
 * 检查认证信息
 * @param authType
 * @returns {boolean}
 */
function checkAuthorization(authType = AUTH_TYPE.BEARER) {
  switch (authType) {
    case AUTH_TYPE.BEARER:
      if (localStorage.getItem(V4_ACCESS_TOKEN) || Cookie.get(V4_ACCESS_TOKEN)) {
        return true
      }
      break
    case AUTH_TYPE.BASIC:
    case AUTH_TYPE.AUTH1:
    case AUTH_TYPE.AUTH2:
    default:
      break
  }
  return false
}

/**
 * 加载 axios 拦截器
 * @param interceptors
 * @param options
 */
function loadInterceptors() {
  // 加载请求拦截器
  axios.interceptors.request.use(config => {
    // ============ 请求去重逻辑 ============
    // POST 请求默认开启去重，可通过 config.dedupe = false 关闭
    // 支持两种策略：reject（拒绝，默认）和 reuse（复用结果）
    const enableDedupe = shouldEnableDedupe(config)

    if (enableDedupe) {
      const requestKey = generateRequestKey(config)
      config._requestKey = requestKey

      // 检查是否有相同请求正在进行
      if (hasPendingRequest(requestKey)) {
        const result = handleDuplicateRequest(requestKey, config)

        if (!result.shouldProceed) {
          if (result.isReuse && result.promise) {
            // 复用策略：不发起真实 HTTP，用 adapter 直接挂到首请求的 Promise
            // 若此处 return config，axios 仍会发请求，且会跳过下方加密逻辑导致明文出站
            config._isReuseRequest = true
            config._reusePromise = result.promise
            config.adapter = cfg =>
              cfg._reusePromise.then(
                data => ({
                  data,
                  status: 200,
                  statusText: 'OK',
                  headers: {},
                  config: cfg,
                  request: { reused: true }
                }),
                err => Promise.reject(err)
              )
          } else {
            // 拒绝策略：直接返回错误
            return Promise.reject(result.error)
          }
        }
      } else {
        // 仅首个同 key 请求加入 pending（复用跟进的请求不再 add）
        const strategy = getDedupeStrategy(config)
        const { signal } = addPendingRequest(requestKey, config, strategy)
        config.signal = signal
      }
    }
    // ============ 去重逻辑结束 ============

    const token = localStorage.getItem(ACCESS_TOKEN)
    // 如果 token 存在
    // 让每个请求携带自定义 token 请根据实际情况自行修改
    if (token) {
      if (config.url !== V4_LOGIN) {
        // V4 环境则添加 V4请求头
        config.headers[V4_ACCESS_TOKEN] = token
        config.headers[ACCESS_TOKEN] = token
      }
    }

    const v4SessionKey = localStorage.getItem(V4_SESSION_KEY)
    // nginx加密支持（用于地方项目 nginx加密）
    // 当 config.nginxEncrypt 为 true、config.aoteEncrypt='nginx'或全局 Vue.mmType='nginx'时启用
    const enableNginxEncrypt = config.nginxEncrypt || config.aoteEncrypt === 'nginx' || (Vue && Vue.mmType === 'nginx')

    if (
      ['post'].includes(config.method.toLowerCase()) &&
      !config._isReuseRequest &&
      !config.url.includes('/logic/openapi/') &&
      !config.url.includes('devApi') &&
      !config.url.includes('auth/login') &&
      config.url.includes('api/af-')
    ) {
      if (config.data && !(config.data instanceof FormData)) {
        if (v4SessionKey) {
          config.data = {
            encrypted: EncryptUtil.AESEncryptCBC(config.data, v4SessionKey)
          }
          config.headers['X-Sec'] = '1'
          config.headers['X-Rand'] = Math.random().toString(36).substr(2, 5)
          config.headers['X-Ts'] = Date.now()
        }
        if (enableNginxEncrypt) {
          // 使用固定的密钥进行 AES ECB 模式加密
          const nginxKey = CryptoJS.enc.Utf8.parse(GanShenMe(Vue.HWQMM))
          if (typeof config.data === 'string') {
            const srcs = CryptoJS.enc.Utf8.parse(config.data)
            config.data = CryptoJS.AES.encrypt(srcs, nginxKey, {
              mode: CryptoJS.mode.ECB,
              padding: CryptoJS.pad.Pkcs7
            }).toString()
          } else {
            const srcs = CryptoJS.enc.Utf8.parse(JSON.stringify(config.data))
            config.data = CryptoJS.AES.encrypt(srcs, nginxKey, {
              mode: CryptoJS.mode.ECB,
              padding: CryptoJS.pad.Pkcs7
            }).toString()
          }
        }
      }
    }

    // 请求v3 时，添加X-Skip-Lua头 避免地方项目 nginx 加密导致请求 不同
    if ([LOGIN, SEARCH].includes(config.url) || config.url.startsWith('/rs/user')) {
      config.headers['X-Skip-Lua'] = 1
    }
    if (!config.headers['Content-Type']) {
      config.headers['Content-Type'] = 'application/json;charset=UTF-8'
    }
    // 处理params参数
    if (config.params) {
      const url = config.url + '?' + qs.stringify(config.params, { indices: false })
      config.params = {}
      config.url = url
    }
    return config
  }, errorHandler)
  // 加载响应拦截器
  axios.interceptors.response.use(res => {
    const requestKey = res.config._requestKey

    // 如果是复用请求，直接返回复用的 Promise 结果
    if (res.config._isReuseRequest && res.config._reusePromise) {
      return res.config._reusePromise
    }

    // 判断是否需要解密
    if (res.headers && res.headers['x-encrypted'] === '1') {
      const v4SessionKey = localStorage.getItem('v4-session-key')
      if (v4SessionKey && res.data) {
        const decryptedData = EncryptUtil.decryptResponse(res?.data, v4SessionKey)
        // 如果解密成功且不等于原数据，说明解密有效
        if (decryptedData !== res.data) {
          // 响应解密成功
          res.data = decryptedData
        }
      }
    }
    if (res.config.nginxEncrypt || res.config.aoteEncrypt === 'nginx' || (Vue && Vue.mmType === 'nginx')) {
      // nginx加密响应解密（支持全局配置）
      if (res.data) {
        try {
          const nginxKey = CryptoJS.enc.Utf8.parse(GanShenMe(Vue?.HWQMM || window.HWQMM))
          const decryptedData = CryptoJS.AES.decrypt(res.data, nginxKey, {
            mode: CryptoJS.mode.ECB,
            padding: CryptoJS.pad.Pkcs7
          }).toString(CryptoJS.enc.Utf8)

          // 如果解密成功（不为空），则使用解密后的数据
          if (decryptedData) {
            try {
              res.data = JSON.parse(decryptedData)
            } catch (e) {
              res.data = decryptedData
            }
          }
        } catch (e) {
          // 解密失败，保持原数据
          console.warn('nginx 解密失败:', e)
        }
      }
    }
    // 判断是否为V4环境，不为compatible赋初始值
    // 其有可能是undefined未定义，或第一次使用本系统LocalStorage在初始化，获得的值为null
    const compatible = getSystemVersion()
    if (compatible === 'V4' || (res.data.code && Object.prototype.hasOwnProperty.call(res.data, 'msg'))) {
      // 请求rul
      const requestUrl = res.config.url
      // 未设置状态码则默认成功状态
      const code = res.data.code || 200
      // 兼容V3, V3使用XFormTable需要这个
      if (res.data.data) {
        if (compatible === 'V4' || (res.config.url.includes('api/af-') && res.data?.data)) {
          res.data = res.data.data
        } else {
          let isJsonArray = false
          if (typeof res.data.data === 'string') {
            try {
              const parsedData = JSON.parse(res.data.data)
              isJsonArray = Array.isArray(parsedData)
            } catch (e) {
              isJsonArray = false
            }
          }
          if (!(Array.isArray(res.data.data) || isJsonArray)) {
            res.data = res.data.data
          }
        }
      }
      // 获取错误信息
      const msg = errorCode[code] || res.data.msg || errorCode.default
      // 二进制数据则直接返回
      if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {
        return res.data
      }
      if (code === 401) {
        if (res.data.msg && localStorage.getItem('SinglePage_TOKEN')) {
          const config = res.config
          return V4RefreshToken()
            .then(res => {
              setV4AccessToken(res)
              return axios(config)
            })
            .catch(extendError => {
              loginExpire()
              return Promise.reject(extendError)
            })
        } else {
          loginExpire()
        }
      } else if (code === 500) {
        if (requestUrl !== '/login' && shouldShowErrorMessage(res.config)) {
          notification.error({
            message: '失败',
            description: msg
          })
        }
      } else if (code === 601) {
        notification.warn({
          message: '警告',
          description: msg
        })
      } else if (code !== 200) {
        if (shouldShowErrorMessage(res.config)) {
          notification.error({
            message: '失败',
            description: msg
          })
        }
      } else {
        // 请求成功，通知复用的请求并返回数据
        if (requestKey) {
          resolvePendingRequest(requestKey, res.data)
        }
        return res.data
      }
      // 请求失败，通知复用的请求
      if (requestKey) {
        rejectPendingRequest(requestKey, new Error(msg))
      }
      return Promise.reject(msg)
    } else {
      // 请求成功，通知复用的请求并返回数据
      if (requestKey) {
        resolvePendingRequest(requestKey, res.data)
      }
      return res.data
    }
  }, errorHandler)
}

function loginExpire() {
  if (!isReloginShow) {
    isReloginShow = true
    if (window.__MICRO_APP_ENVIRONMENT__) {
      logout().then(() => {
        isReloginShow = false
      })
    } else {
      notification.open({
        message: '系统提示',
        description: '登录状态已过期，请重新登录',
        btn: h => {
          return h(
            'a-button',
            {
              props: {
                type: 'primary',
                size: 'small'
              },
              on: {
                click: () => {
                  logout().then(() => {
                    isReloginShow = false
                    location.href = '/login'
                  })
                }
              }
            },
            '确认'
          )
        },
        duration: 0,
        onClose: () => {
          isReloginShow = false
        }
      })
    }
  }
}
// 异常拦截处理器
const errorHandler = error => {
  // 请求失败，通知复用的请求并移除 pending 记录
  if (error.config) {
    const requestKey = error.config._requestKey
    if (requestKey) {
      rejectPendingRequest(requestKey, error)
    }
  }

  // 如果是被取消的请求（去重导致或 AbortController），静默处理
  // 支持 axios.isCancel()、AbortController、ERR_CANCELED、ERR_DUPLICATE_REQUEST
  if (
    axios.isCancel(error) ||
    error.name === 'CanceledError' ||
    error.code === 'ERR_CANCELED' ||
    error.code === 'ERR_DUPLICATE_REQUEST'
  ) {
    return Promise.reject(error)
  }

  if (error.response) {
    const data = error.response.data
    // 从 localstorage 获取 token
    const token = localStorage.getItem(ACCESS_TOKEN)
    if (error.response.status === 403 || (data && data.code === 403)) {
      notification.error({
        message: '禁止访问',
        description: data
      })
    } else if (error.response.status === 401 || (data && data.code === 401)) {
      notification.error({
        message: '鉴权失败',
        description: data
      })
      if (token) {
        logout().then(() => {
          setTimeout(() => {
            window.location.reload()
          }, 1500)
        })
      }
    } else if (error.response.status === 500 || (data && data.code === 500)) {
      if (shouldShowErrorMessage(error.config)) {
        notification.error({
          message: '系统异常',
          description: data
        })
      }
    } else if (error.response.status === 601 || (data && data.code === 601)) {
      notification.warn({
        message: '系统警告',
        description: data
      })
    } else if (error.response.status === 413 || (data && data.code === 413)) {
      notification.warn({
        message: '上传的文件过大',
        description: '请检查文件内容'
      })
    } else {
      notification.error({
        message: '网络异常',
        description: data
      })
    }
  }
  return Promise.reject(error)
}

/**
 * 解析 url 中的参数
 * @param url
 * @returns {Object}
 */
function parseUrlParams(url) {
  const params = {}
  if (!url || url === '' || typeof url !== 'string') {
    return params
  }
  const paramsStr = url.split('?')[1]
  if (!paramsStr) {
    return params
  }
  const paramsArr = paramsStr.replace(/&|=/g, ' ').split(' ')
  for (let i = 0; i < paramsArr.length / 2; i++) {
    const value = paramsArr[i * 2 + 1]
    params[paramsArr[i * 2]] = value === 'true' ? true : value === 'false' ? false : value
  }
  return params
}

export {
  METHOD,
  AUTH_TYPE,
  request,
  setAuthorization,
  removeAuthorization,
  checkAuthorization,
  loadInterceptors,
  parseUrlParams
}
