import axios, { type AxiosRequestConfig } from 'axios'
import { MsgError } from '@/utils/message'
import type { NProgress } from 'nprogress'
import type { Ref } from 'vue'
import router from '@/router'

import { ref, type WritableComputedRef } from 'vue'


class Result<T> {
  message: string;
  code: number;
  data: T;
  constructor(message: string, code: number, data: T) {
    this.message = message;
    this.code = code;
    this.data = data;
  }

  static success(data: any) {
    return new Result("请求成功", 200, data);
  }
  static error(message: string, code: number) {
    return new Result(message, code, null);
  }
}

interface Page<T> {
  /**
   *分页数据
   */
  records: Array<T>;
  /**
   *当前页
   */
  current: number;
  /**
   * 每页展示size
   */
  size: number;
  /**
   *总数
   */
  total: number;
  /**
   *是否有下一页
   */
  hasNext: boolean;
}



const axiosConfig = {
  baseURL: '/ai-doc/api',
  withCredentials: false,
  timeout: 1000 * 60 * 60,
  headers: {}
}

const instance = axios.create(axiosConfig)

/* 设置请求拦截器 */
instance.interceptors.request.use(
  (config: AxiosRequestConfig) => {
    return config
  },
  (err: any) => {
    return Promise.reject(err)
  }
)

//设置响应拦截器
instance.interceptors.response.use(
  (response: any) => {
    if (response.data) {
      if (+response.data.status !== 0 && !(response.data instanceof Blob)) {
        if(+response.data.status === 403) {
          MsgError(response.data.msg)
          localStorage.setItem('token', '')
          return window.location.reload()
        }
        if(+response.data.status === 500) {
          MsgError(response.data.msg)
        }
        return Promise.reject(response.data)
      }
    }
    return response
  },
  (err: any) => {
    // || err.code === 'ERR_BAD_RESPONSE'
    if (err.code === 'ECONNABORTED') {
      MsgError(err.message)
      console.error(err)
    }
    if (err.response?.status === 404) {
      if (!err.response.config.url.includes('/application/authentication')) {
        router.push('/404 ')
      }
    }
    if (err.response?.status === 401) {
     
      if(err.response.data.code === 1002 && err.response.data.message !== '登录过期' ) {
        MsgError(err.response.data.message)
        // 添加 非法用户！认证信息不正确 场景
        if(err.response.data.message === '非法用户！认证信息不正确') {
          router.push({ name: 'login' })
        }
      } else
      if (
        !err.response.config.url.includes('chat/open') &&
        !err.response.config.url.includes('application/profile')
      ) {
        router.push({ name: 'login' })
      }
    }

    if (err.response?.status === 403 && !err.response.config.url.includes('chat/open')) {
      MsgError(
        err.response.data && err.response.data.message ? err.response.data.message : '没有权限访问'
      )
    }
    return Promise.reject(err)
  }
)

export const request = instance

/* 简化请求方法，统一处理返回结果，并增加loading处理，这里以{success,data,message}格式的返回值为例，具体项目根据实际需求修改 */
const promise: (
  request: Promise<any>,
  loading?: NProgress | Ref<boolean> | WritableComputedRef<boolean>
) => Promise<Result<any>> = (request, loading = ref(false)) => {
  return new Promise((resolve, reject) => {
    if ((loading as NProgress).start) {
      ;(loading as NProgress).start()
    } else {
      ;(loading as Ref).value = true
    }
    request
      .then((response) => {
        // blob类型的返回状态是response.status
        if (response.status === 200) {
          resolve(response?.data || response)
        } else {
          reject(response?.data || response)
        }
      })
      .catch((error) => {
        reject(error)
      })
      .finally(() => {
        if ((loading as NProgress).start) {
          ;(loading as NProgress).done()
        } else {
          ;(loading as Ref).value = false
        }
      })
  })
}

/**
 * 发送get请求   一般用来请求资源
 * @param url    资源url
 * @param params 参数
 * @param loading loading
 * @param headers 请求头
 * @param timeout 超时时间
 * @returns 异步promise对象
 */
export const get: (
  url: string,
  params?: unknown,
  loading?: NProgress | Ref<boolean>,
  headers?: any,
  timeout?: number
) => Promise<Result<any>> = (
  url: string,
  params: unknown,
  loading?: NProgress | Ref<boolean>,
  headers?: any,
  timeout?: number,
) => {
  return promise(request({ url: url, method: 'get', params, headers, timeout }), loading)
}

/**
 * faso post请求 一般用来添加资源
 * @param url    资源url
 * @param params 参数
 * @param data   添加数据
 * @param loading loading
 * @param headers 请求头
 * @param timeout 超时时间
 * @returns 异步promise对象
 */
export const post: (
  url: string,
  data?: unknown,
  params?: unknown,
  loading?: NProgress | Ref<boolean>,
  headers?: any,
  timeout?: number
) => Promise<Result<any> | any> = (url, data, params, loading, headers, timeout) => {
  return promise(request({ url: url, method: 'post', data, params, headers, timeout }), loading)
}

/**|
 * 发送put请求 用于修改服务器资源
 * @param url     资源地址
 * @param params  params参数地址
 * @param data    需要修改的数据
 * @param loading 进度条
 * @returns
 */
export const put: (
  url: string,
  data?: unknown,
  params?: unknown,
  loading?: NProgress | Ref<boolean>,
  timeout?: number
) => Promise<Result<any>> = (url, data, params, loading, timeout) => {
  return promise(request({ url: url, method: 'put', data, params, timeout }), loading)
}

/**
 * 删除
 * @param url     删除url
 * @param params  params参数
 * @param loading 进度条
 * @returns
 */
export const del: (
  url: string,
  params?: unknown,
  data?: unknown,
  loading?: NProgress | Ref<boolean>,
  timeout?: number
) => Promise<Result<any>> = (url, params, data, loading, timeout) => {
  return promise(request({ url: url, method: 'delete', params, data, timeout }), loading)
}

/**
 * 流处理
 * @param url  url地址
 * @param data 请求body
 * @returns
 */
export const postStream1: (url: string, data?: any, token?: any) => Promise<Result<any> | any> = (
  url,
  data,
  token
) => {
  const headers: HeadersInit = { 'Content-Type': 'application/json' }
  if (token) {
    headers['AUTHORIZATION'] = `${token}`
  }
  return fetch(url, {
    method: 'POST',
    body: data ? JSON.stringify(data) : undefined,
    headers: headers
  })
}

/**
 * 流处理
 * @param url  url地址
 * @param data 请求body
 * @returns
 */
export const postStream: (url: string, data?: unknown) => Promise<Result<any> | any> = (
  url,
  data
) => {
  const headers: HeadersInit = { 'Content-Type': 'application/json' }
  return fetch(url, {
    method: 'POST',
    body: data ? JSON.stringify(data) : undefined,
    headers: headers
  })
}

/**
 * 流处理
 * @param url  url地址
 * @param data 请求body
 * @returns
 */
export const postStreamSse: (url: string, data?: unknown) => Promise<Result<any> | any> = (
  url,
  data
) => {
  const headers: HeadersInit = { 'Content-Type': 'application/json' }
  return fetch(url, {
    method: 'POST',
    body: data ? JSON.stringify(data) : undefined,
    headers: headers
  })
}

export const exportExcel: (
  fileName: string,
  url: string,
  params: any,
  loading?: NProgress | Ref<boolean>
) => Promise<any> = (
  fileName: string,
  url: string,
  params: any,
  loading?: NProgress | Ref<boolean>
) => {
  return promise(request({ url: url, method: 'get', params, responseType: 'blob' }), loading).then(
    (res: any) => {
      if (res) {
        const blob = new Blob([res], {
          type: 'application/vnd.ms-excel'
        })
        const link = document.createElement('a')
        link.href = window.URL.createObjectURL(blob)
        link.download = fileName
        link.click()
        //释放内存
        window.URL.revokeObjectURL(link.href)
      }
      return true
    }
  )
}

export const exportFile: (
  fileName: string,
  url: string,
  params: any,
  loading?: NProgress | Ref<boolean>
) => Promise<any> = (
  fileName: string,
  url: string,
  params: any,
  loading?: NProgress | Ref<boolean>
) => {
  return promise(request({ url: url, method: 'get', params, responseType: 'blob' }), loading).then(
    (res: any) => {
      if (res) {
        const blob = new Blob([res], {
          type: 'application/octet-stream'
        })
        const link = document.createElement('a')
        link.href = window.URL.createObjectURL(blob)
        link.download = fileName
        link.click()
        //释放内存
        window.URL.revokeObjectURL(link.href)
      }
      return true
    }
  )
}

export const exportExcelPost: (
  fileName: string,
  url: string,
  params: any,
  data: any,
  loading?: NProgress | Ref<boolean>
) => Promise<any> = (
  fileName: string,
  url: string,
  params: any,
  data: any,
  loading?: NProgress | Ref<boolean>
) => {
  return promise(
    request({
      url: url,
      method: 'post',
      params, // 查询字符串参数
      data, // 请求体数据
      responseType: 'blob'
    }),
    loading
  ).then((res: any) => {
    if (res) {
      const blob = new Blob([res], {
        type: 'application/vnd.ms-excel'
      })
      const link = document.createElement('a')
      link.href = window.URL.createObjectURL(blob)
      link.download = fileName
      link.click()
      // 释放内存
      window.URL.revokeObjectURL(link.href)
    }
    return true
  })
}

export const download: (
  url: string,
  method: string,
  data?: any,
  params?: any,
  loading?: NProgress | Ref<boolean>
) => Promise<any> = (
  url: string,
  method: string,
  data?: any,
  params?: any,
  loading?: NProgress | Ref<boolean>
) => {
  return promise(request({ url: url, method: method, data, params, responseType: 'blob' }), loading)
}

/**
 * 与服务器建立ws链接
 * @param url websocket路径
 * @returns  返回一个websocket实例
 */
export const socket = (url: string) => {
  let protocol = 'ws://'
  if (window.location.protocol === 'https:') {
    protocol = 'wss://'
  }
  let uri = protocol + window.location.host + url
  if (!import.meta.env.DEV) {
    uri = protocol + window.location.host + import.meta.env.VITE_BASE_PATH + url
  }
  return new WebSocket(uri)
}
export default instance
