/**
 * 解析智能体 SSE（data: {...}）行
 */

export function createSseLineBuffer() {
	let pending = ''

	return {
		push(chunkText) {
			if (!chunkText) return []
			pending += chunkText
			const lines = []
			let pos = 0
			while (true) {
				const end = pending.indexOf('\n', pos)
				if (end === -1) break
				lines.push(pending.slice(pos, end))
				pos = end + 1
			}
			pending = pending.slice(pos)
			return lines
		},
		flushLine() {
			if (!pending) return null
			const line = pending
			pending = ''
			return line
		}
	}
}

export function parseConsoleChatSseLine(line) {
	const trimmed = (line || '').trim()
	if (!trimmed || trimmed.startsWith(':')) return null
	if (!trimmed.startsWith('data:')) return null

	const payload = trimmed.slice(5).trim()
	if (!payload || payload === '[DONE]') {
		return { done: true }
	}

	try {
		return { data: JSON.parse(payload) }
	} catch (e) {
		return null
	}
}

/**
 * 从 SSE JSON 中提取 assistant 文本片段（可能是增量，也可能是累计全文）
 */
export function extractAssistantDelta(data) {
	if (!data || typeof data !== 'object') return ''

	if (data.error) {
		const err = data.error
		const msg = (typeof err === 'string' ? err : (err.message || err.msg)) || 'AI 服务异常'
		throw new Error(msg)
	}

	const parts = []
	const output = data.output
	if (Array.isArray(output)) {
		for (const item of output) {
			if (!item || item.role !== 'assistant' || !Array.isArray(item.content)) continue
			for (const block of item.content) {
				if (block && block.type === 'text' && block.text) {
					parts.push(block.text)
				}
			}
		}
	}

	// 顶层 assistant message：content[{ type:text, text }]
	if (!parts.length && data.role === 'assistant' && Array.isArray(data.content)) {
		for (const block of data.content) {
			if (block && (block.type === 'text' || !block.type) && block.text) {
				parts.push(block.text)
			}
		}
	}

	if (!parts.length && typeof data.text === 'string') parts.push(data.text)
	// delta 事件：data.delta 可能是布尔；真正增量在 data.text
	if (!parts.length && typeof data.delta === 'string') parts.push(data.delta)

	return parts.join('')
}

function commonPrefixLength(a, b) {
	const n = Math.min(a.length, b.length)
	let i = 0
	while (i < n && a.charAt(i) === b.charAt(i)) i += 1
	return i
}

function longestSuffixPrefixOverlap(a, b) {
	const max = Math.min(a.length, b.length)
	for (let len = max; len >= 1; len -= 1) {
		if (a.endsWith(b.slice(0, len))) return len
	}
	return 0
}

/**
 * 识别「流式全文 + 终态快照略有改写」——本应替换，不能再拼接
 */
function isLikelyFullSnapshotRewrite(cur, next) {
	const minLen = Math.min(cur.length, next.length)
	if (minLen < 40) return false

	const prefix = commonPrefixLength(cur, next)
	if (prefix >= 24 && prefix / minLen >= 0.55) return true

	const window = Math.min(24, minLen)
	const lenDiffRatio = Math.abs(cur.length - next.length) / minLen
	if (cur.slice(0, window) === next.slice(0, window) && lenDiffRatio < 0.35) {
		return true
	}

	// 开头 20 字互相靠近出现，且长度接近 → 几乎是同一段答案被再推一次
	if (minLen >= 60) {
		const head = next.slice(0, 20)
		const curHead = cur.slice(0, 20)
		if (cur.indexOf(head) <= 8 && next.indexOf(curHead) <= 8 && lenDiffRatio < 0.4) {
			return true
		}
	}
	return false
}

/** 流式乱码（UTF-8 截断）后终态全文应优先替换 */
function shouldPreferCleanSnapshot(cur, next) {
	if (!cur || !next) return false
	if (cur.indexOf('\uFFFD') === -1) return false
	const lenDiffRatio = Math.abs(cur.length - next.length) / Math.max(cur.length, next.length)
	if (lenDiffRatio > 0.35) return false
	const prefix = commonPrefixLength(cur.replace(/\uFFFD+/g, ''), next)
	return prefix >= 6 || commonPrefixLength(cur, next) >= 6
}

/**
 * 合并流式 assistant 文本，兼容：
 * - 增量 token（直接拼接）
 * - 累计全文快照（startsWith 则替换）
 * - 结束包重复推送整段答案（去重，含轻微改写）
 * - 流式解码乱码后用终态干净全文覆盖
 */
export function mergeAssistantStreamText(current, incoming) {
	const cur = current || ''
	const next = incoming || ''
	if (!next) return cur
	if (!cur) return next
	if (next === cur) return cur
	// 上游发「到目前为止的全文」或最终完整包
	if (next.startsWith(cur)) return next
	// 迟到的旧快照
	if (cur.startsWith(next)) return cur
	if (shouldPreferCleanSnapshot(cur, next)) return next
	// 整段答案被再次推送（略有改写也按快照替换，避免首尾拼成两段）
	if (isLikelyFullSnapshotRewrite(cur, next)) {
		return next.length >= cur.length ? next : cur
	}
	if (next.length >= 8 && cur.endsWith(next)) return cur
	if (cur.length >= 8 && next.indexOf(cur) === 0) return next
	// 缝合点去重：cur 尾部与 next 头部重叠
	const overlap = longestSuffixPrefixOverlap(cur, next)
	if (overlap >= 20 || (overlap >= 8 && overlap >= Math.min(cur.length, next.length) * 0.2)) {
		return cur + next.slice(overlap)
	}
	return cur + next
}
