import { useEffect, useRef, useState } from "react";
import { fetchSessionHistory } from "../../api/sessions";
import { useChatContext } from "../../context/ChatContext";
import type { ChatMessage, ToolCallBlock } from "../../types/message";
import { extractContent, extractThinking, formatToolCall, getToolCalls } from "../../utils/toolCall";
import { nextMessageId } from "../../utils/format";
import {
	downloadTextFile,
	messagesToMarkdown,
	messagesToMinimalHtml,
	safeExportFilename,
} from "../../utils/exportConversation";
import styles from "./ExportMenu.module.css";

function historyToExportMessages(
	messages: NonNullable<Awaited<ReturnType<typeof fetchSessionHistory>>["messages"]>,
): ChatMessage[] {
	const result: ChatMessage[] = [];
	for (const m of messages) {
		if (m.role === "user") {
			result.push({ id: nextMessageId(), role: "user", content: extractContent(m.content) });
		} else if (m.role === "assistant") {
			if (Array.isArray(m.content)) {
				for (const block of m.content) {
					if (block.type === "thinking") {
						const thinking = (block.thinking ?? "").trim();
						if (thinking) {
							result.push({ id: nextMessageId(), role: "thinking", content: thinking });
						}
					} else if (block.type === "text") {
						const text = (block.text ?? "").trim();
						if (text) {
							result.push({ id: nextMessageId(), role: "assistant", content: text });
						}
					} else if (block.type === "toolCall") {
						const tc = block as ToolCallBlock;
						const tid = tc.toolCallId || tc.id;
						result.push({
							id: tid ? `tool-${tid}` : nextMessageId(),
							role: "tool_call",
							content: formatToolCall(tc),
							toolCallId: tid ? String(tid) : undefined,
						});
					}
				}
			} else {
				const thinking = extractThinking(m.content);
				if (thinking) {
					result.push({ id: nextMessageId(), role: "thinking", content: thinking });
				}
				const text = extractContent(m.content);
				if (text) result.push({ id: nextMessageId(), role: "assistant", content: text });
				for (const tc of getToolCalls(m.content)) {
					const tid = tc.toolCallId || tc.id;
					result.push({
						id: tid ? `tool-${tid}` : nextMessageId(),
						role: "tool_call",
						content: formatToolCall(tc),
						toolCallId: tid ? String(tid) : undefined,
					});
				}
			}
		}
	}
	return result;
}

export function ExportMenu({ compact = false }: { compact?: boolean }) {
	const { headerTitle, messages, activeSessionPath, isStreaming, addSystemMessage } = useChatContext();
	const [open, setOpen] = useState(false);
	const [exporting, setExporting] = useState(false);
	const wrapRef = useRef<HTMLDivElement>(null);

	const hasMessages = messages.some((m) => !m.streaming && m.content.trim());
	const canExport = hasMessages && !isStreaming && !exporting;

	useEffect(() => {
		if (!open) return;
		const onPointerDown = (event: MouseEvent) => {
			if (!wrapRef.current?.contains(event.target as Node)) {
				setOpen(false);
			}
		};
		const onKeyDown = (event: KeyboardEvent) => {
			if (event.key === "Escape") setOpen(false);
		};
		document.addEventListener("mousedown", onPointerDown);
		document.addEventListener("keydown", onKeyDown);
		return () => {
			document.removeEventListener("mousedown", onPointerDown);
			document.removeEventListener("keydown", onKeyDown);
		};
	}, [open]);

	const resolveExportMessages = async (): Promise<ChatMessage[]> => {
		if (activeSessionPath) {
			try {
				const payload = await fetchSessionHistory(activeSessionPath);
				if (payload.messages?.length) {
					return historyToExportMessages(payload.messages);
				}
			} catch {
				/* fallback to in-memory messages */
			}
		}
		return messages;
	};

	const handleExport = async (format: "markdown" | "html") => {
		if (!canExport) return;
		setExporting(true);
		setOpen(false);
		try {
			const exportMessages = await resolveExportMessages();
			const filtered = exportMessages.filter((m) => !m.streaming && m.content.trim());
			if (!filtered.length) {
				addSystemMessage("当前对话没有可导出的内容");
				return;
			}
			const title = headerTitle.trim() || "对话";
			const base = safeExportFilename(title);
			if (format === "markdown") {
				downloadTextFile(`${base}.md`, messagesToMarkdown(title, filtered), "text/markdown");
			} else {
				downloadTextFile(`${base}.html`, messagesToMinimalHtml(title, filtered), "text/html");
			}
		} catch (err) {
			addSystemMessage(`导出失败: ${err instanceof Error ? err.message : String(err)}`);
		} finally {
			setExporting(false);
		}
	};

	return (
		<div className={styles.wrap} ref={wrapRef}>
			<button
				type="button"
				className={compact ? `${styles.btn} ${styles.btnIcon}` : styles.btn}
				disabled={!canExport}
				aria-expanded={open}
				aria-haspopup="menu"
				aria-label="导出对话"
				onClick={() => setOpen((value) => !value)}
			>
				<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
					<path d="M12 3v12M7 8l5 5 5-5M5 21h14" />
				</svg>
				{compact ? null : "导出"}
			</button>
			{open ? (
				<div className={styles.menu} role="menu">
					<button type="button" className={styles.menuItem} role="menuitem" onClick={() => void handleExport("markdown")}>
						Markdown
						<span className={styles.menuItemDesc}>.md 格式，保留 Markdown 结构</span>
					</button>
					<button type="button" className={styles.menuItem} role="menuitem" onClick={() => void handleExport("html")}>
						HTML 超简洁文本
						<span className={styles.menuItemDesc}>纯文本风格 HTML，便于阅读与分享</span>
					</button>
				</div>
			) : null}
		</div>
	);
}
