import { getToken } from "@/api/request.js";

const CHART_INTERPRETATION_URL = "/aiAnalysis/chart_interpretation";
const API_KEY = "aircasKEY19491001";

/**
 * 从模型返回的 markdown code fence 中提取数组 JSON
 * 例如：```json\n[ ... ]\n```
 * @param {string} buffer
 * @returns {unknown[]}
 */
function parseChartInterpretationArray(buffer) {
	// 可能带有前后空白、换行、以及 ```/```json 包裹
	let cleaned = String(buffer || "").trim();

	// 移除开头 fence
	cleaned = cleaned.replace(/^```(?:json)?\s*/i, "");
	// 移除结尾 fence（允许末尾有换行）
	cleaned = cleaned.replace(/```[\s\r\n]*$/i, "").trim();

	// 优先直接解析
	try {
		const parsed = JSON.parse(cleaned);
		if (Array.isArray(parsed)) return parsed;
	} catch (_) { }

	// 兜底：从 first '[' 到 last ']' 截取
	const start = cleaned.indexOf("[");
	const end = cleaned.lastIndexOf("]");
	if (start !== -1 && end !== -1 && end > start) {
		const arrStr = cleaned.slice(start, end + 1);
		const parsed = JSON.parse(arrStr);
		if (Array.isArray(parsed)) return parsed;
	}

	throw new Error("无法解析图表解读 JSON 数组");
}

/**
 * 从数组结果中提取可展示的解读文本
 * @param {unknown[]} arr
 * @returns {string}
 */
function pickInterpretationText(arr) {
	if (!Array.isArray(arr) || arr.length === 0) {
		return "";
	}
	const first = arr[0] || {};
	return (
		first["解读"] ||
		first["interpretation"] ||
		first["analysis"] ||
		first["content"] ||
		""
	);
}

/**
 * 从非标准 JSON 文本中兜底提取“解读”字段（兼容单引号/双引号）
 * 示例：
 * [{'图表标题': '数量变化趋势', '解读': 'xxx'}]
 * [{"图表标题":"数量变化趋势","解读":"xxx"}]
 * @param {string} text
 * @returns {string}
 */
function extractInterpretationFromLooseText(text) {
	const raw = String(text || "");
	if (!raw) {
		return "";
	}
	const reg =
		/["']解读["']\s*:\s*["']([\s\S]*?)["']\s*(?:[,}\]])/;
	const m = raw.match(reg);
	if (!m || !m[1]) {
		return "";
	}
	return String(m[1]).replace(/\\n/g, "\n").trim();
}

/**
 * 从流式累积 buffer 中提取「解读」字符串的已生成部分（滤掉 ```json、[、{ 等外壳，避免界面出现 json\n[\n）
 * 支持未闭合的字符串（流式进行中）
 * @param {string} buffer
 * @returns {string}
 */
function extractStreamingInterpretationFromBuffer(buffer) {
	const s = String(buffer || "");
	let rest = s.replace(/^\uFEFF/, "");
	const fence = rest.match(/^```(?:json)?\s*/i);
	if (fence) {
		rest = rest.slice(fence[0].length);
	}
	const keyRe =
		/["'](?:解读|interpretation|analysis|content)["']\s*:\s*"/i;
	const m = rest.match(keyRe);
	if (!m) {
		return "";
	}
	let pos = m.index + m[0].length;
	let out = "";
	while (pos < rest.length) {
		const ch = rest[pos];
		if (ch === '"') {
			break;
		}
		if (ch === "\\") {
			pos += 1;
			if (pos >= rest.length) {
				break;
			}
			const esc = rest[pos];
			if (esc === "n") {
				out += "\n";
			} else if (esc === "r") {
				out += "\r";
			} else if (esc === "t") {
				out += "\t";
			} else if (esc === '"' || esc === "\\") {
				out += esc;
			} else {
				out += esc;
			}
			pos += 1;
			continue;
		}
		out += ch;
		pos += 1;
	}
	return out;
}

/**
 * 图表解读（SSE 流式）
 * @param {object} data - 请求体
 * @param {object} [options] - 可选配置
 * @param {function(string): void} [options.onChunk] - 每收到一条 SSE 消息时回调，参数为当前 chunk 的 text
 * @returns {Promise<{data: unknown[]}>}
 */
export function getChartAnalysis(data, options = {}) {
	const onDelta =
		typeof options?.onChunk === "function"
			? options.onChunk
			: typeof options?.onInterpretationDelta === "function"
				? options.onInterpretationDelta
				: null;
	const externalSignal = options?.signal;
	return new Promise((resolve, reject) => {
		let buffer = "";
		let latestInterpretation = "";
		/** 已推给前端的「解读」正文长度，用于只增量回调 onChunk */
		let lastStreamedInterpretationLen = 0;
		let settled = false;
		const abortController = new AbortController();
		const externalAbortHandler = () => {
			abortController.abort();
		};
		if (externalSignal) {
			if (externalSignal.aborted) {
				abortController.abort();
			} else {
				externalSignal.addEventListener("abort", externalAbortHandler, { once: true });
			}
		}

		const safeResolve = value => {
			if (settled) return;
			settled = true;
			if (externalSignal) {
				externalSignal.removeEventListener("abort", externalAbortHandler);
			}
			resolve(value);
		};

		const safeReject = err => {
			if (settled) return;
			settled = true;
			if (externalSignal) {
				externalSignal.removeEventListener("abort", externalAbortHandler);
			}
			reject(err);
		};

		(async () => {
			try {
				const { fetchEventSource } = await import("@microsoft/fetch-event-source");

				await fetchEventSource(CHART_INTERPRETATION_URL, {
					method: "POST",
					headers: {
						"Content-Type": "application/json",
						Accept: "text/event-stream",
						"Cache-Control": "no-cache",
						"X-API-Key": API_KEY,
						// 后端同项目其它接口使用 token 字段名（axios 拦截器里就是这样注入的）
						token: getToken()
					},
					body: JSON.stringify(data),
					signal: abortController.signal,
					openWhenHidden: true,
					retryDelay: 1000,
					maxRetries: 2,
					onopen: response => {
						const contentType = response.headers.get("content-type") || "";
						if (!contentType.includes("text/event-stream")) {
							throw new Error("SSE连接格式异常：content-type 不是 text/event-stream");
						}
					},
					onmessage: event => {
						const raw = (event?.data || "").trim();
						if (!raw) return;
						if (raw === "[DONE]") return;

						let chunk = "";
						// 兼容后端返回格式：
						// - {"text":"```"} / {"text":"json\n[\n"}
						// - {"type":"reasoning","chunk":"..."}（新格式）
						try {
							const msg = JSON.parse(raw);
							if (Array.isArray(msg?.chunk)) {
								safeResolve({ data: msg.chunk });
								abortController.abort();
								return;
							}

							if (msg && typeof msg === "object" && "chunk" in msg) {
								chunk = typeof msg.chunk === "string" ? msg.chunk : "";
								if (chunk) buffer += chunk;
							} else if (msg && typeof msg === "object" && "text" in msg) {
								chunk = String(msg.text ?? "");
								if (chunk) buffer += chunk;
							} else {
								chunk = raw;
								buffer += raw;
							}
						} catch (e) {
							chunk = raw;
							buffer += raw;
						}

						// 兜底：非标准 JSON（如单引号 Python 风格）时，尝试直接从文本提取“解读”
						const looseInterpretation = extractInterpretationFromLooseText(raw);
						if (looseInterpretation) {
							latestInterpretation = looseInterpretation;
							safeResolve({ data: [{ 解读: looseInterpretation }] });
							abortController.abort();
							return;
						}

						// 流式渲染：不把 ```json、[、{ 等 markdown/JSON 外壳拼到界面
						if (chunk && onDelta) {
							let parsedMsg = null;
							try {
								parsedMsg = JSON.parse(raw);
							} catch (_) {
								parsedMsg = null;
							}
							const isReasoningChunk =
								parsedMsg &&
								typeof parsedMsg === "object" &&
								parsedMsg.type === "reasoning" &&
								typeof parsedMsg.chunk === "string";

							if (isReasoningChunk) {
								onDelta(parsedMsg.chunk);
							} else {
								const visible = extractStreamingInterpretationFromBuffer(buffer);
								if (visible.length > lastStreamedInterpretationLen) {
									onDelta(
										visible.slice(lastStreamedInterpretationLen)
									);
									lastStreamedInterpretationLen = visible.length;
								}
							}
						}

						// 如果 buffer 已经拼完 markdown code fence，则提前解析并中断连接
						const trimmed = buffer.trim();
						if (trimmed.endsWith("```")) {
							try {
								const arr = parseChartInterpretationArray(trimmed);
								const interpretation = pickInterpretationText(arr);
								if (interpretation) {
									latestInterpretation = interpretation;
								}
								safeResolve({ data: arr });
								abortController.abort();
							} catch (_) { }
						}
					},
					onclose: () => {
						try {
							const arr = parseChartInterpretationArray(buffer);
							const interpretation = pickInterpretationText(arr);
							if (interpretation) {
								latestInterpretation = interpretation;
							}
							safeResolve({ data: arr });
						} catch (e) {
							// 兜底：整体 buffer 不是标准 JSON（如单引号）时直接提取“解读”
							const looseInterpretation = extractInterpretationFromLooseText(buffer);
							if (looseInterpretation) {
								safeResolve({ data: [{ 解读: looseInterpretation }] });
								return;
							}
							if (latestInterpretation) {
								safeResolve({ data: [{ 解读: latestInterpretation }] });
								return;
							}
							safeReject(e);
						}
					},
					onerror: error => {
						if (error?.name === "AbortError") return true;
						safeReject(error);
						return true;
					}
				});
			} catch (error) {
				safeReject(error);
			}
		})();
	});
}
