/**
 * @Description: request 封装（支持流式请求，修复onComplete兼容性问题）
 * @Version: 1.0.4
 * @author: 
 * @Date: 2025-08-25
 */
import { requestConfig } from '../app.config.js'
import api from '@/api/index.js'
// import { TextDecoder } from 'text-encoding';

class Request {
	constructor() {
		this.isRefreshing = false; // 是否正在刷新token的标记
		this.subscribers = []; // 缓存等待token刷新的请求
		this.tokenKey = 'token';
		this.refreshTokenKey = 'refresh_token';

		// 绑定方法确保this上下文
		this.http = this.http.bind(this);
		this.streamHttp = this.streamHttp.bind(this);
		this.refreshToken = this.refreshToken.bind(this);
		this.buildRequestConfig = this.buildRequestConfig.bind(this);
		this.handleError = this.handleError.bind(this);
	}

	// 获取token
	getToken() {
		return uni.getStorageSync(this.tokenKey);
	}

	// 获取刷新token
	getRefreshToken() {
		return uni.getStorageSync(this.refreshTokenKey);
	}

	// 保存token
	saveToken(token) {
		uni.setStorageSync(this.tokenKey, token);
	}

	// 保存刷新token
	saveRefreshToken(refreshToken) {
		uni.setStorageSync(this.refreshTokenKey, refreshToken);
	}

	// 清除token
	clearToken() {
		uni.removeStorageSync(this.tokenKey);
		uni.removeStorageSync(this.refreshTokenKey);
	}

	// 触发用户信息刷新
	triggerUserInfoRefresh() {
		uni.$emit("userinfoRefresh", true);
	}

	// 添加等待token刷新的请求
	addSubscriber(callback) {
		this.subscribers.push(callback);
	}

	// 执行等待中的请求
	resolveSubscribers() {
		this.subscribers.forEach(callback => callback());
		this.subscribers = [];
	}

	// 无感刷新token
	async refreshToken() {
		if (this.isRefreshing) {
			// 如果正在刷新，返回一个Promise等待刷新完成
			return new Promise(resolve => {
				this.addSubscriber(() => resolve(this.http(...arguments)));
			});
		}

		this.isRefreshing = true;

		try {
			const refreshToken = this.getRefreshToken();
			if (!refreshToken) {
				throw new Error('刷新令牌不存在');
			}

			const res = await api.login({
				grant_type: 'refresh',
				refresh_token: refreshToken,
				client_type: 0,
			});

			if (res.code === 200) {
				this.saveToken(`Bearer ${res.data.access_token}`);
				this.saveRefreshToken(res.data.refresh_token);
				this.triggerUserInfoRefresh();
				this.resolveSubscribers();
				return true;
			} else {
				throw new Error(res.msg || '令牌刷新失败');
			}
		} catch (error) {
			console.error('令牌刷新错误:', error);
			this.clearToken();
			uni.redirectTo({
				url:
					"/pages/index/index?shopId=" + uni.getStorageSync('shopId'),
			});
			return false;
		} finally {
			// 延迟释放刷新标记，避免并发请求问题
			setTimeout(() => {
				this.isRefreshing = false;
			}, 1000);
		}
	}

	// 处理请求错误
	handleError(error, param, isStream = false) {
		if (error.code === 501) {
			// 令牌过期，尝试刷新
			return this.refreshToken().then(refreshed => {
				if (refreshed) {
					// 刷新成功后重试请求，区分普通和流式请求
					return isStream ? this.streamHttp(param) : this.http(param);
				}
				throw error; // 刷新失败，抛出错误
			});
		}
		throw error; // 其他错误直接抛出
	}

	// 构建请求配置
	buildRequestConfig(param) {
		const {
			url,
			method = 'GET',
			data,
			params,
			header = {},
			responseType = 'text',
			type,
			enableChunked,
			timeout

		} = param;

		// 合并请求头
		const headers = {
			'Content-Type': 'application/x-www-form-urlencoded',
			...header
		};
		console.log(headers);

		// 添加授权信息
		const token = this.getToken();
		// if (token && !headers['Authorization']) {
		// 	headers['Authorization'] = 'Bearer ' + token;
		// }

		// 流式请求需要特殊处理
		if (param.isStream) {
			headers['Accept'] = 'text/event-stream';
		}
		console.log(requestConfig);

		// 构建请求URL
		const BaseUrl = requestConfig.BaseUrl;
		const requestUrl = BaseUrl + url;

		return {
			url: requestUrl,
			data: data || params,
			method,
			dataType: 'json',
			responseType,
			header: headers,
			enableChunked,
			timeout: timeout,
		};
	}

	// 主请求方法（普通请求）
	http(param) {
		return new Promise((resolve, reject) => {
			try {
				const requestConfig = this.buildRequestConfig(param);
				// 从参数中获取是否显示错误提示的标志
				const showToast = param.showToast !== undefined ? param.showToast : true;
				let isAborted = false;

				// 创建请求任务
				const requestTask = uni.request({
					...requestConfig,
					success: (res) => {
						if (isAborted) return;

						// HTTP状态码检查	
						if (res.statusCode !== 200) {
							const error = new Error(
								`API错误: ${res.data.error || res.statusCode}`);
							error.response = res;
							if (showToast) uni.$u.toast(error.message);
							reject(error);
							return;
						}

						// 业务逻辑错误处理
						if (res.data.code !== 200) {
							if (res.data.code === 501) {
								// 令牌过期，处理刷新
								// this.handleError({ code: 501 }, param)
								// 	.then(refreshedRes => resolve(refreshedRes))
								// 	.catch(err => reject(err));
								
								uni.reLaunch({
									url:
										"/pages/index/index?shopId=" + uni.getStorageSync('shopId'),
								});	
								localStorage.clear();
							} else if (res.data.code === 400 && res.data.msg === '登录凭证不为空') {
								const error = new Error(res.data.msg);
								error.response = res;
								
								// if (showToast) {
								uni.reLaunch({
									url:
										"/pages/index/index?shopId=" + uni.getStorageSync('shopId'),
								});
								localStorage.clear();
								// }
								reject(error);
							} else {
								const error = new Error(res.data.msg || '请求失败');
								if (showToast) uni.$u.toast(error.message);
								reject(res);
							}
							return;
						}

						// 正常响应
						resolve(res.data);
					},
					fail: (err) => {
						if (isAborted) return;
						const error = new Error('网络异常, 请检查网络连接');
						error.originalError = err;
						if (showToast) uni.$u.toast(error.message);
						reject(error);
					}
				});

				// 终止请求的方法
				const abort = () => {
					isAborted = true;
					if (requestTask.abort) {
						console.log('中断请求成功！');
						requestTask.abort();
					}
					if (typeof param.onAbort === 'function') {
						param.onAbort();
					}
				};

				// 暴露终止方法
				if (typeof param.onInit === 'function') {
					param.onInit(abort);
				}
			} catch (error) {
				// 统一错误处理
				console.error('请求处理错误:', error);
				error.isRequestError = true;
				reject(error);
			}
		});
	}

	// 流式请求方法
	streamHttp(param) {
		return new Promise((resolve, reject) => {
			// 标记为流式请求
			param.isStream = true;
			const requestConfig = this.buildRequestConfig(param);
			const showToast = param.showToast !== undefined ? param.showToast : true;
			let isAborted = false;
			let complete = false;
			let lastChunkTime = 0; // 记录最后一次接收数据的时间

			// 设置超时检测，无数据传输时判断为结束
			const timeoutInterval = 500000; // 5分钟无数据则视为结束
			const checkTimeout = () => {
				if (complete || isAborted) return;

				const now = Date.now();
				if (lastChunkTime > 0 && now - lastChunkTime > timeoutInterval) {
					// 超时，视为请求完成
					finish();
				} else {
					// 继续检测
					setTimeout(checkTimeout, 1000);
				}
			};

			// 创建请求任务
			const requestTask = uni.request({
				...requestConfig,
				// 流式请求需要设置响应类型为arraybuffer
				responseType: 'arraybuffer',
				success: (res) => {
					if (res.statusCode !== 200) {
						const error = new Error(`API错误: ${res.statusCode}`);
						error.response = res;
						if (showToast) uni.$u.toast(error.message);
						reject(error);
						return;
					}
				},
				fail: (err) => {
					if (isAborted) return;
					const error = new Error('网络异常, 请检查网络连接');
					error.originalError = err;
					if (showToast) uni.$u.toast(error.message);
					reject(error);
				}
			});

			// 处理流式数据
			// const decoder = new TextDecoder('utf-8');

			// 检查请求任务是否支持onChunkReceived方法
			if (typeof requestTask.onChunkReceived !== 'function') {
				reject(new Error('当前环境不支持流式请求'));
				return;
			}

			// 监听数据块
			requestTask.onChunkReceived((response) => {
				if (isAborted || complete) return;

				// 更新最后接收数据的时间
				lastChunkTime = Date.now();

				// 处理token过期情况
				if (response.statusCode === 401 || (response.data && response.data.code === 501)) {
					this.handleError({ code: 501 }, param, true)
						.then(() => {
							// 刷新成功后会重新发起请求，这里终止当前流
							abort();
						})
						.catch(err => {
							if (!complete) {
								complete = true;
								reject(err);
							}
						});
					return;
				}

				// 解码二进制数据
				const chunk = this.decodeUtf8(response.data)
				// const chunk = decoder.decode(response.data, { stream: true });
				// 检查是否是结束标记（根据实际后端约定调整）
				if (chunk.includes('[DONE]') || chunk.includes('</stream>') || chunk.includes('result')) {
					// 调用流式回调处理最后一块数据
					if (typeof param.onChunk === 'function') {
						param.onChunk(chunk.replace(/\[DONE\]|<\/stream>/g, ''), response);
					}
					finish();
					return;
				}

				// 调用流式回调处理数据
				if (typeof param.onChunk === 'function') {
					param.onChunk(chunk, response);
				}
			});

			// 监听请求头接收
			if (typeof requestTask.onHeadersReceived === 'function') {
				requestTask.onHeadersReceived((response) => {
					if (response.statusCode === 200 && typeof param.onOpen === 'function') {
						param.onOpen(response);
						// 收到响应头后开始超时检测
						lastChunkTime = Date.now();
						setTimeout(checkTimeout, 1000);
					}
				});
			} else {
				// 如果不支持onHeadersReceived，直接开始超时检测
				setTimeout(checkTimeout, 1000);
			}

			// 终止请求的方法
			const abort = () => {
				isAborted = true;
				if (requestTask.abort) {
					requestTask.abort();
				}
				if (typeof param.onAbort === 'function') {
					param.onAbort();
				}
			};

			// 完成回调
			const finish = () => {
				if (complete) return;
				complete = true;
				if (typeof param.onComplete === 'function') {
					param.onComplete();
				}
				resolve();
			};

			// 暴露终止方法
			if (typeof param.onInit === 'function') {
				param.onInit(abort);
			}
		});
	}
	// 新增：手动实现 UTF-8 解码（替换 TextDecoder）
	decodeUtf8(arrayBuffer) {
		const uint8Array = new Uint8Array(arrayBuffer);
		let str = '';
		let i = 0;
		const len = uint8Array.length;

		while (i < len) {
			const byte = uint8Array[i];
			let codePoint;

			// 单字节字符（0-127）
			if (byte < 0x80) {
				codePoint = byte;
				i += 1;
			}
			// 双字节字符（128-2047）
			else if (byte >= 0xC0 && byte < 0xE0) {
				codePoint = ((byte & 0x1F) << 6) | (uint8Array[i + 1] & 0x3F);
				i += 2;
			}
			// 三字节字符（2048-65535）
			else if (byte >= 0xE0 && byte < 0xF0) {
				codePoint = ((byte & 0x0F) << 12) | ((uint8Array[i + 1] & 0x3F) << 6) | (uint8Array[i + 2] & 0x3F);
				i += 3;
			}
			// 四字节字符（Unicode 扩展平面）
			else if (byte >= 0xF0 && byte < 0xF8) {
				codePoint = ((byte & 0x07) << 18) | ((uint8Array[i + 1] & 0x3F) << 12) | ((uint8Array[i + 2] & 0x3F) << 6) | (uint8Array[i + 3] & 0x3F);
				i += 4;
			}
			// 无效字节（跳过）
			else {
				i += 1;
				continue;
			}

			// 处理四字节字符的代理对
			if (codePoint <= 0xFFFF) {
				str += String.fromCharCode(codePoint);
			} else {
				codePoint -= 0x10000;
				const high = (codePoint >> 10) & 0x3FF;
				const low = codePoint & 0x3FF;
				str += String.fromCharCode(0xD800 + high, 0xDC00 + low);
			}
		}

		return str;
	}
}

export default new Request();
