import type { ChatMessage, ContentBlock, ImageContent, ToolCallBlock } from "../types/message";

export function isToolCallComplete(content: string): boolean {
	const trimmed = content.trimStart();
	return trimmed.startsWith("✅") || trimmed.startsWith("❌");
}

export function preferToolCallMessage(existing: ChatMessage, incoming: ChatMessage): ChatMessage {
	const existingComplete = isToolCallComplete(existing.content);
	const incomingComplete = isToolCallComplete(incoming.content);
	let content = existing.content;
	if (incomingComplete && !existingComplete) {
		content = incoming.content;
	} else if (incomingComplete === existingComplete) {
		content =
			incoming.content.length >= existing.content.length ? incoming.content : existing.content;
	}
	return {
		...existing,
		content,
		toolCallId: existing.toolCallId ?? incoming.toolCallId,
	};
}

export function upsertToolCallMessage(result: ChatMessage[], message: ChatMessage): void {
	if (message.toolCallId) {
		const idx = result.findIndex(
			(msg) => msg.role === "tool_call" && msg.toolCallId === message.toolCallId,
		);
		if (idx >= 0) {
			result[idx] = preferToolCallMessage(result[idx], message);
			return;
		}
	}
	const idIdx = result.findIndex((msg) => msg.id === message.id);
	if (idIdx >= 0) {
		result[idIdx] = preferToolCallMessage(result[idIdx], message);
		return;
	}
	result.push(message);
}

export function extractContent(content: string | ContentBlock[] | undefined): string {
	if (!content) return "";
	if (typeof content === "string") return content;
	if (Array.isArray(content)) {
		return content
			.filter((c) => c.type === "text")
			.map((c) => c.text ?? "")
			.join("");
	}
	return String(content);
}

export function extractThinking(content: string | ContentBlock[] | undefined): string {
	if (!content) return "";
	if (typeof content === "string") return "";
	if (!Array.isArray(content)) return "";
	return content
		.filter((c) => c.type === "thinking")
		.map((c) => c.thinking ?? "")
		.join("\n\n")
		.trim();
}

export function deriveThinkingSummary(content: string, maxLen = 56): string {
	const oneLine = String(content || "").replace(/\s+/g, " ").trim();
	if (!oneLine) return "思考中…";
	if (oneLine.length <= maxLen) return oneLine;
	return `${oneLine.slice(0, maxLen).trimEnd()}…`;
}

export function extractImages(content: string | ContentBlock[] | undefined): ImageContent[] {
	if (!Array.isArray(content)) return [];
	return content
		.filter((c): c is ImageContent => c.type === "image" && typeof c.data === "string" && !!c.mimeType)
		.map((c) => ({ type: "image", data: c.data, mimeType: c.mimeType }));
}

export function getToolCalls(content: string | ContentBlock[] | undefined): ToolCallBlock[] {
	if (!Array.isArray(content)) return [];
	return content.filter((c): c is ToolCallBlock => c.type === "toolCall");
}

export function formatToolCall(tc: ToolCallBlock): string {
	const name = tc.toolName || tc.name || "tool";
	const args = tc.arguments ?? tc.args ?? tc.input ?? {};
	let text = `${name}(${JSON.stringify(args)})`;
	const shortId = tc.toolCallId || tc.id;
	if (shortId) text = `# ${String(shortId).slice(0, 8)}\n${text}`;
	return text;
}

export function formatToolResult(tr: { content?: unknown }): string {
	let text = "";
	const content = tr.content;
	if (typeof content === "string") text = content;
	else if (Array.isArray(content)) {
		text = content.map((c) => (c && typeof c === "object" && "text" in c ? String(c.text) : JSON.stringify(c))).join("\n");
	} else if (content && typeof content === "object" && "text" in content) {
		text = String((content as { text: string }).text);
	} else {
		text = JSON.stringify(content || tr, null, 2);
	}
	return text.length > 800 ? `${text.slice(0, 800)}\n… (已截断)` : text;
}

export function formatToolBodyHtml(content: string): string {
	const lines = content.split("\n");
	let inDiff = false;
	const htmlLines = lines.map((line) => {
		if (/^(\+\+\+|---|@@)/.test(line.trim())) {
			inDiff = true;
			return `<span class="diffMeta">${escapeHtml(line)}</span>`;
		}
		if (inDiff && line.startsWith("+")) {
			return `<span class="diffAdd">${escapeHtml(line)}</span>`;
		}
		if (inDiff && line.startsWith("-")) {
			return `<span class="diffDel">${escapeHtml(line)}</span>`;
		}
		return escapeHtml(line);
	});
	return htmlLines.join("\n");
}

function escapeHtml(text: string): string {
	return text
		.replace(/&/g, "&amp;")
		.replace(/</g, "&lt;")
		.replace(/>/g, "&gt;");
}

export function deriveToolCallSummary(fullText: string): string {
	const raw = String(fullText || "").trim();
	if (!raw) return "tool";
	let icon = "";
	if (raw.startsWith("🔧")) icon = "🔧";
	else if (raw.startsWith("✅")) icon = "✅";
	else if (raw.startsWith("❌")) icon = "❌";
	const rest = icon ? raw.slice(icon.length).trimStart() : raw;
	const idLine = rest.split("\n").find((l) => l.trimStart().startsWith("# "));
	const idPart = idLine ? idLine.replace(/^\s*#\s*/, "").trim().split(/\s/)[0] : "";
	const oneLine = rest.replace(/\s+/g, " ");
	const nameMatch = oneLine.match(/(\w+)\s*\(/);
	const name = nameMatch ? nameMatch[1] : "tool";
	let label = idPart ? `${name} · ${idPart}` : name;
	if (icon) label = `${icon} ${label}`;
	return label;
}

export function buildToolCallUpdateText(
	ev: { toolName: string; partialResult?: { content?: unknown }; result?: { content?: unknown } },
	isError?: boolean,
): string {
	const icon = isError === undefined ? "🔧" : isError ? "❌" : "✅";
	let detail = "";
	if (ev.partialResult?.content) {
		detail = `\n${formatToolResult(ev.partialResult)}`;
	}
	if (isError !== undefined) {
		const resultText = ev.result?.content ? `\n${formatToolResult(ev.result)}` : "";
		return `${icon} ${ev.toolName}${resultText || detail}`;
	}
	return `${icon} ${ev.toolName}${detail}`;
}
