/**
 * uni.request 统一封装
 * 
 * 设计目标：
 * 1. 自动兼容项目中所有 API 的成功状态判断（code === 200 / code === 1 / status === 200）
 * 2. 支持自定义 header、超时、baseURL
 * 3. Promise 化，调用简单
 * 4. 支持请求/响应拦截器（便于后续统一注入 token、处理错误等）
 * 5. 数据提取自动降级：优先取 res.data.data，不存在则取 res.data
 */

class Request {
	/**
	 * @param {Object} config - 全局默认配置
	 * @param {string} config.baseURL - 基础 URL
	 * @param {number} config.timeout - 超时时间（ms），默认 30000
	 * @param {Object} config.header - 默认请求头
	 */
	constructor(config = {}) {
		this.config = {
			baseURL: '',
			timeout: 30000,
			header: {
				'Content-Type': 'application/json'
			},
			...config
		};
		this.interceptors = {
			request: [],
			response: []
		};
	}

	/**
	 * 添加请求拦截器
	 * @param {Function} fn - (config) => config
	 */
	addRequestInterceptor(fn) {
		if (typeof fn === 'function') {
			this.interceptors.request.push(fn);
		}
	}

	/**
	 * 添加响应拦截器
	 * @param {Function} fn - (response) => response
	 */
	addResponseInterceptor(fn) {
		if (typeof fn === 'function') {
			this.interceptors.response.push(fn);
		}
	}

	/**
	 * 判断响应是否成功
	 * 
	 * 兼容项目中实际存在的 4 种响应格式：
	 * 1. CMS API:    res.data.code === 200
	 * 2. Auth API:   res.statusCode === 200 && (res.data.status === 200 || res.data.code === 1)
	 * 3. Hdk v2 API: res.data.code === 1
	 * 4. 兜底:       res.statusCode === 200（无业务状态码时）
	 * 
	 * @param {Object} res - uni.request 的 success 回调参数
	 * @returns {boolean}
	 */
	isSuccess(res) {
		// HTTP 层已失败（如 404/500）
		if (res.statusCode >= 400) {
			return false;
		}

		const data = res.data;
		if (!data || typeof data !== 'object') {
			// 无响应体时，以 HTTP 状态码为准
			return res.statusCode === 200;
		}

		// 提取业务状态码（兼容 code / status 两种字段名）
		const code = data.code !== undefined ? Number(data.code)
			: data.status !== undefined ? Number(data.status)
			: null;

		if (code !== null && !isNaN(code)) {
			return code === 200 || code === 1;
		}

		// 无业务状态码时，以 HTTP 状态码为准
		return res.statusCode === 200;
	}

	/**
	 * 从响应中提取业务数据
	 * 
	 * 降级策略：
	 * - 优先取 res.data.data（CMS 标准格式）
	 * - 不存在则取 res.data 本身（直接返回格式）
	 * - 空响应返回 null
	 * 
	 * @param {Object} res - uni.request 的 success 回调参数
	 * @returns {any}
	 */
	extractData(res) {
		const data = res.data;
		if (!data || typeof data !== 'object') {
			return data;
		}
		return data.data !== undefined ? data.data : data;
	}

	/**
	 * 从响应中提取错误信息
	 * @param {Object} res - uni.request 的 success 回调参数
	 * @returns {string}
	 */
	extractError(res) {
		const data = res.data;
		if (!data || typeof data !== 'object') {
			return `请求失败 (HTTP ${res.statusCode})`;
		}
		return data.msg || data.message || data.error || `请求失败 (code: ${data.code || data.status})`;
	}

	/**
	 * 核心请求方法
	 * 
	 * @param {Object} options - 请求配置
	 * @param {string} options.url - 请求地址（可相对 baseURL）
	 * @param {string} options.method - 请求方法：GET/POST/PUT/DELETE，默认 GET
	 * @param {Object} options.data - 请求数据
	 * @param {Object} options.header - 自定义请求头（会合并覆盖默认 header，大小写不敏感）
	 * @param {number} options.timeout - 本次请求单独设置的超时时间
	 * @returns {Promise<{success: true, data: any, body: any, raw: Object}>}
	 */
	request(options = {}) {
		return new Promise((resolve, reject) => {
			// 1. 合并配置：默认 → 实例配置 → 单次请求配置
			// header 合并需大小写不敏感去重（如 Content-Type 与 content-type 是同一头）
			const mergedHeader = {};
			for (const [k, v] of Object.entries(this.config.header)) {
				mergedHeader[k.toLowerCase()] = v;
			}
			for (const [k, v] of Object.entries(options.header || {})) {
				mergedHeader[k.toLowerCase()] = v;
			}
			let config = {
				...this.config,
				...options,
				header: mergedHeader
			};

			// 2. 拼接 baseURL（如果 url 不是完整 HTTP 地址）
			if (config.baseURL && config.url && !config.url.startsWith('http')) {
				config.url = config.baseURL.replace(/\/$/, '') + '/' + config.url.replace(/^\//, '');
			}

			// 3. 执行请求拦截器
			try {
				for (const fn of this.interceptors.request) {
					config = fn(config) || config;
				}
			} catch (err) {
				reject({ success: false, message: err.message || '请求拦截器异常', code: -2 });
				return;
			}

			// 4. 发起请求
			uni.request({
				url: config.url,
				method: (config.method || 'GET').toUpperCase(),
				data: config.data,
				header: config.header,
				timeout: config.timeout,
				success: (res) => {
					// 5. 执行响应拦截器
					try {
						for (const fn of this.interceptors.response) {
							res = fn(res) || res;
						}
					} catch (err) {
						reject({ success: false, message: err.message || '响应拦截器异常', code: -3, raw: res });
						return;
					}

					// 6. 判断成功/失败
					if (this.isSuccess(res)) {
						resolve({
							success: true,
							data: this.extractData(res),
							body: res.data,
							raw: res
						});
					} else {
						reject({
							success: false,
							message: this.extractError(res),
							code: res.data?.code ?? res.data?.status ?? res.statusCode,
							raw: res
						});
					}
				},
				fail: (err) => {
					reject({
						success: false,
						message: err.errMsg || '网络请求失败，请检查网络',
						code: -1,
						raw: err
					});
				}
			});
		});
	}

	/**
	 * GET 请求快捷方法
	 * @param {string} url
	 * @param {Object} data
	 * @param {Object} options
	 */
	get(url, data, options = {}) {
		return this.request({ url, data, method: 'GET', ...options });
	}

	/**
	 * POST 请求快捷方法
	 * @param {string} url
	 * @param {Object} data
	 * @param {Object} options
	 */
	post(url, data, options = {}) {
		return this.request({ url, data, method: 'POST', ...options });
	}

	/**
	 * PUT 请求快捷方法
	 */
	put(url, data, options = {}) {
		return this.request({ url, data, method: 'PUT', ...options });
	}

	/**
	 * DELETE 请求快捷方法
	 */
	delete(url, data, options = {}) {
		return this.request({ url, data, method: 'DELETE', ...options });
	}
}

// ============================================================
// 创建全局默认实例
// ============================================================
const http = new Request();

// ============================================================
// 导出
// ============================================================
export default http;
export { Request };
