// utils/http.ts
/*
 *
 * 　　┏┓　　　┏┓+ +
 * 　┏┛┻━━━┛┻┓ + +
 * 　┃　　　　　　　┃
 * 　┃　　　━　　　┃ ++ + + +
 *  ████━████ ┃+
 * 　┃　　　　　　　┃ +
 * 　┃　　　┻　　　┃
 * 　┃　　　　　　　┃ + +
 * 　┗━┓　　　┏━┛
 * 　　　┃　　　┃
 * 　　　┃　　　┃ + + + +
 * 　　　┃　　　┃
 * 　　　┃　　　┃ +  神兽保佑
 * 　　　┃　　　┃    代码无bug
 * 　　　┃　　　┃　　+
 * 　　　┃　 　　┗━━━┓ + +
 * 　　　┃ 　　　　　　　┣┓
 * 　　　┃ 　　　　　　　┏┛
 * 　　　┗┓┓┏━┳┓┏┛ + + + +
 * 　　　　┃┫┫　┃┫┫
 * 　　　　┗┻┛　┗┻┛+ + + +
 */
import type { RequestTask } from '@dcloudio/types'
import type { UniRequestConfig, UniResponse } from '@dcloudio/uni-app'

// 定义基础响应类型
export interface HttpResponse<T = any> {
	code : number
	message : string
	data : T
	[key : string] : any
}

// 请求配置类型
export interface RequestConfig extends UniRequestConfig {
	baseURL ?: string
	retry ?: number // 重试次数
	retryDelay ?: number // 重试延迟时间(ms)
	loading ?: boolean // 是否显示加载状态
	headers ?: Record<string, string>
	timeout ?: number
	skipAuth ?: boolean // 是否跳过认证检查
}

// 定义 Token 类型
export interface TokenData {
	value : string
	expire : number
}

// 拦截器类型
interface Interceptor<V> {
	fulfilled : (value : V) => V | Promise<V>
	rejected ?: (error : any) => any
}

export class HttpClient {
	private defaults : RequestConfig
	private interceptors : {
		request : Interceptor<RequestConfig>[]
		response : Interceptor<UniResponse<HttpResponse>>[]
	}
	private pendingRequests : Map<string, RequestTask>

	// 新增刷新相关属性
	private isRefreshing = false
	private refreshSubscribers : ((token : string) => void)[] = []

	constructor(config : RequestConfig = {}) {
		this.defaults = {
			baseURL: '',
			timeout: 10000,
			retry: 0,
			retryDelay: 1000,
			loading: false,
			...config
		}

		this.interceptors = {
			request: [],
			response: []
		}
		this.pendingRequests = new Map()
	}

	//token检查方法
	static checkTokenValidity(token : any) : string | null {
		let tokenValue : string | null = null
		let tokenExpire : number | null = null
		try {
			if (token) {
				// 处理字符串类型的token（可能是JSON或原始字符串）
				if (typeof token === 'string') {
					try {
						// 尝试解析为JSON对象
						const parsed = JSON.parse(token)
						if (parsed && typeof parsed.value === 'string') {
							tokenValue = parsed.value
							tokenExpire = parsed.expire
						} else {
							// 不是有效JSON对象，当作原始token字符串
							tokenValue = token
						}
					} catch (e) {
						// JSON解析失败，当作原始token字符串
						tokenValue = token
					}
				}
				else if (typeof token === 'object' && token.value) {
					tokenValue = token.value
					tokenExpire = token.expire
				}
				if (tokenValue) {
					const now = Date.now() + 10000 // 10秒缓冲
					// 如果有过期时间则检查，否则认为有效
					if (tokenExpire) {
						return tokenExpire > now ? tokenValue : null
					}
					return tokenValue
				}
			}
		} catch (e) {
			console.error('Token 有效性检查失败:', e)
		}
		return null
	}

	private createRequestKey(config : RequestConfig) : string {
		return `${config.method}-${config.url}-${JSON.stringify(config.data)}`
	}

	// token刷新
	private async refreshToken() : Promise<void> {
		try {
			const refreshToken = uni.getStorageSync('refreshToken');
			const tokenValue = HttpClient.checkTokenValidity(refreshToken);

			const response = await this.request<{
				accessToken : string;
				refreshToken : string;
			}>({
				url: `/member/auth/refresh-token?refreshToken=${tokenValue}`,
				method: 'POST',
				data: '',
				skipAuth: true
			});

			uni.setStorageSync('token', response.accessToken);
			uni.setStorageSync('refreshToken', response.refreshToken);

			this.refreshSubscribers.forEach(callback => callback(response.accessToken));
			this.refreshSubscribers = [];
		} catch (error) {
			console.error('刷新Token失败:', error);
			uni.removeStorageSync('token');
			uni.removeStorageSync('refreshToken');
			uni.reLaunch({ url: '/pages/login/selectLogin' });
			throw error;
		} finally {
			this.isRefreshing = false;
		}
	}

	// 核心方法增加无感刷新逻辑
	async request<T = any>(config : RequestConfig) : Promise<T> {
		let mergedConfig : RequestConfig = { ...this.defaults, ...config }
		// 执行请求拦截器
		for (const interceptor of this.interceptors.request) {
			try {
				mergedConfig = await interceptor.fulfilled(mergedConfig)
			} catch (error) {
				interceptor.rejected?.(error)
				throw error
			}
		}
		const requestKey = this.createRequestKey(mergedConfig)
		// 取消重复请求
		if (this.pendingRequests.has(requestKey)) {
			this.pendingRequests.get(requestKey)?.abort()
		}

		return new Promise((resolve, reject) => {
			const sendRequest = async (retryCount = 0) => {
				if (mergedConfig.loading) {
					uni.showLoading({ title: '加载中...', mask: true })
				}

				try {
					const task = uni.request({
						...mergedConfig,
						url: mergedConfig.baseURL + mergedConfig.url,
						success: async (response) => {
							const res = response.data as HttpResponse;
							if (res.code === 401 && !mergedConfig.skipAuth) {
								const retryOriginalRequest = new Promise<T>((resolve) => {
									this.refreshSubscribers.push((newToken) => {
										// 使用新Token重试请求
										const retryConfig = {
											...mergedConfig,
											header: {
												...mergedConfig.header,
												Authorization: `Bearer ${newToken}`
											}
										}
										this.request(retryConfig).then(resolve)
									})
								})
								if (!this.isRefreshing) {
									this.isRefreshing = true
									this.refreshToken().catch((error) => {
										this.refreshSubscribers = []
										reject(error)
									})
								}
								return resolve(await retryOriginalRequest)
							}
							// 执行响应拦截器
							let processedResponse = response
							for (const interceptor of this.interceptors.response) {
								try {
									processedResponse = await interceptor.fulfilled(processedResponse)
								} catch (error) {
									interceptor.rejected?.(error)
									reject(error)
									return
								}
							}

							const resData = processedResponse.data as HttpResponse<T>
							if (resData.code === 0) {
								resolve(resData.data)
							} else {
								uni.showToast({
									title: resData.msg || '请求失败',
									icon: 'none'
								})
								reject(resData)
							}
						},
						fail: async (error) => {
							// 重试逻辑
							if (retryCount < mergedConfig.retry!) {
								setTimeout(() => {
									sendRequest(retryCount + 1)
								}, mergedConfig.retryDelay)
							} else {
								reject(error)
							}
						},
						complete: () => {
							this.pendingRequests.delete(requestKey)
							if (mergedConfig.loading) {
								uni.hideLoading()
							}
						}
					}) as RequestTask

					this.pendingRequests.set(requestKey, task)
				} catch (error) {
					reject(error)
				}
			}
			sendRequest()
		})
	}

	// 添加请求拦截器
	useRequestInterceptor(interceptor : Interceptor<RequestConfig>) {
		this.interceptors.request.push(interceptor)
	}

	// 添加响应拦截器
	useResponseInterceptor(interceptor : Interceptor<UniResponse<HttpResponse>>) {
		this.interceptors.response.push(interceptor)
	}

	// 快捷方法
	get<T = any>(url : string, config ?: RequestConfig) {
		return this.request<T>({ ...config, url, method: 'GET' })
	}

	post<T = any>(url : string, data ?: any, config ?: RequestConfig) {
		return this.request<T>({ ...config, url, data, method: 'POST' })
	}

	delete<T = any>(url : string, data ?: any, config ?: RequestConfig) {
		return this.request<T>({ ...config, url, data, method: 'DELETE' })
	}

	put<T = any>(url : string, data ?: any, config ?: RequestConfig) {
		return this.request<T>({ ...config, url, data, method: 'PUT' })
	}
}

// 创建实例
export const http = new HttpClient({
	baseURL: 'http://qhmall.natapp1.cc/app-api',
	headers: {
		'Content-Type': 'application/json'
	}
})

// 添加请求拦截器 - 处理鉴权
http.useRequestInterceptor({
	fulfilled: (config) => {
		// 跳过不需要认证的请求
		if (config.skipAuth) return config
		const tokenStorage = uni.getStorageSync('token')
		// 检查 token 有效性并提取值
		const tokenValue = HttpClient.checkTokenValidity(tokenStorage)
		if (tokenValue) {
			config.header = config.header || {}
			config.header.Authorization = `Bearer ${tokenValue}`
		} else {
			console.log('[请求拦截器] 无有效Token')
		}
		return config
	}
})

// 添加响应拦截器 - 错误处理
http.useResponseInterceptor({
	fulfilled: (response) => {
		const resData = response.data as HttpResponse;
		if (resData.code !== 0) {
			return Promise.reject(response)
		}
		return response
	},
	rejected: (error) => {
		console.log(error.data, 'err');
		uni.showToast({
			title: error.data.msg || '请求失败',
			icon: 'none'
		})
		return Promise.reject(error)
	}
})