<template>
	<div class="streaming-status">
		<message-item
			v-if="pendingUserMessage"
			:message="pendingUserMessage"
		/>

		<thinking-block
			v-if="streamingThinkingDisplay"
			:content="streamingThinkingDisplay"
			:is-streaming="loading"
		/>

		<message-item
			v-if="shouldShowStreamingMessage"
			:message="streamingMessage"
		/>

		<div v-if="hasStatusContent" class="stream-card">
			<div class="stream-card__head">
				<span class="entry-chip">流式执行</span>
				<span class="stream-status">{{ streamingError ? '失败' : '运行中' }}</span>
			</div>
			<div v-if="visibleStreamingTools.length" class="stream-tools">
				<template v-for="tool in visibleStreamingToolViews" :key="tool.key">
					<todo-card
						v-if="tool.toolName === 'todo' && parseTodoResult(tool.result)"
						:items="parseTodoResult(tool.result)!.items"
						:summary="parseTodoResult(tool.result)!.summary"
					/>
					<template v-else-if="tool.toolName === 'clarify' && props.pendingClarify" />
					<div
						v-else
						class="stream-tool"
						:class="`stream-tool--${tool.status}`"
					>
						<div class="stream-tool__head">
							<span>{{ tool.label }}</span>
							<strong>{{ tool.statusLabel }}</strong>
						</div>
						<div v-if="shouldShowStreamingToolRuntimeMeta(tool)" class="stream-tool__meta">
							<span>{{ runtimeRouteLabel(tool.runtimeRoute) }}</span>
							<span v-if="tool.workerRoutingHint">{{ workerRoutingHintLabel(tool.workerRoutingHint) }}</span>
							<span v-if="tool.blockedReason">{{ blockedReasonLabel(tool.blockedReason) }}</span>
						</div>
						<div v-if="tool.processDisplay.latest" class="stream-tool__process">
							<el-progress
								v-if="typeof tool.processDisplay.latest?.percent === 'number'"
								:percentage="tool.processDisplay.latest!.percent!"
								:stroke-width="4"
								:show-text="false"
							/>
							<span class="stream-tool__process-message">
								{{ tool.processDisplay.latest!.label }}
								<small v-if="tool.processDisplay.latest?.detail">{{ tool.processDisplay.latest!.detail }}</small>
							</span>
						</div>
						<tool-process-timeline :events="tool.processEvents" />
						<pre v-if="tool.showArgs && tool.args" class="stream-tool__args">{{ stringifyContent(tool.args) }}</pre>
						<pre
							v-if="tool.result"
							class="stream-tool__result"
							:class="{ 'is-collapsed': !isStreamingToolExpanded(tool.key) && tool.isLongResult }"
						>{{ tool.result }}</pre>
						<button
							v-if="tool.isLongResult"
							class="stream-tool__toggle"
							@click="emit('toggle-tool', tool.key)"
						>
							{{ isStreamingToolExpanded(tool.key) ? '收起结果' : '展开结果' }}
						</button>
					</div>
				</template>
			</div>
			<p v-if="streamingError" class="stream-card__error">{{ streamingError }}</p>
		</div>

		<clarify-card
			v-if="pendingClarify"
			:message="clarifyMessage"
			@answer="(requestId, answer) => emit('clarify-answer', requestId, answer)"
		/>
	</div>
</template>

<script lang="ts" setup>
import { computed } from 'vue';
import MessageItem from '../message-item.vue';
import ThinkingBlock from '../thinking-block.vue';
import TodoCard from '../todo-card.vue';
import ClarifyCard from '../clarify-card.vue';
import ToolProcessTimeline from '../tool-process-timeline.vue';
import type { ChatMessage, RuntimeProcessEventProjection, TodoItem, TodoSummary, ToolRuntimeRouteProjection } from '../../types/index.d';
import { buildToolProcessDisplay } from '../../utils/tool-process-display';

type StreamingToolView = {
	key: string;
	status: string;
	label: string;
	statusLabel: string;
	toolName?: string;
	runtimeRoute?: ToolRuntimeRouteProjection['runtimeRoute'];
	workerRoutingHint?: ToolRuntimeRouteProjection['workerRoutingHint'];
	blockedReason?: string | null;
	showArgs?: boolean;
	args?: unknown;
	result?: string;
	isLongResult?: boolean;
	latestProcessEvent?: RuntimeProcessEventProjection;
	processEvents?: RuntimeProcessEventProjection[];
};

type StreamingToolDisplayView = StreamingToolView & {
	processDisplay: ReturnType<typeof buildToolProcessDisplay>;
};

const props = defineProps<{
	loading: boolean;
	streamingError: string;
	hasStatusContent: boolean;
	pendingUserMessage: ChatMessage | null;
	shouldShowStreamingMessage: boolean;
	streamingThinkingDisplay: string;
	visibleStreamingTools: StreamingToolView[];
	streamingMessage: ChatMessage;
	shouldShowStreamingToolRuntimeMeta: (tool: StreamingToolView) => boolean;
	runtimeRouteLabel: (route?: ToolRuntimeRouteProjection['runtimeRoute']) => string;
	workerRoutingHintLabel: (hint?: ToolRuntimeRouteProjection['workerRoutingHint']) => string;
	blockedReasonLabel: (reason?: string | null) => string;
	stringifyContent: (content: unknown) => string;
	isStreamingToolExpanded: (toolCallId: string) => boolean;
	pendingClarify: { requestId: string; question: string; choices: string[] } | null;
}>();

const emit = defineEmits<{
	'toggle-tool': [toolCallId: string];
	'clarify-answer': [requestId: string, answer: string];
}>();

const clarifyMessage = computed<ChatMessage>(() => ({
	role: 'clarify' as any,
	content: props.pendingClarify?.question || '',
	metadata: {
		requestId: props.pendingClarify?.requestId,
		choices: props.pendingClarify?.choices || [],
		status: 'pending',
	},
	createTime: '',
}));

const visibleStreamingToolViews = computed<StreamingToolDisplayView[]>(() => props.visibleStreamingTools.map(tool => ({
	...tool,
	processDisplay: buildToolProcessDisplay(tool.processEvents || (tool.latestProcessEvent ? [tool.latestProcessEvent] : [])),
})));

const _todoCache = new Map<string, { items: TodoItem[]; summary: TodoSummary | null } | null>();

function parseTodoResult(result?: string): { items: TodoItem[]; summary: TodoSummary | null } | null {
	if (!result) return null;
	const cached = _todoCache.get(result);
	if (cached !== undefined) return cached;
	try {
		const parsed = JSON.parse(result);
		const todos = parsed?.todos || parsed?.items;
		if (!Array.isArray(todos) || !todos.length) {
			_todoCache.set(result, null);
			return null;
		}
		const items: TodoItem[] = todos.map((t: any, i: number) => ({
			id: String(t.id ?? i),
			content: String(t.content || t.title || t.text || ''),
			status: t.status || 'pending',
		}));
		const summary: TodoSummary | null = parsed?.summary ?? null;
		const value = { items, summary };
		_todoCache.set(result, value);
		return value;
	} catch {
		_todoCache.set(result, null);
		return null;
	}
}

</script>

<style lang="scss" scoped>
.stream-tool__process {
	margin-top: 8px;
	display: grid;
	gap: 6px;
}

.stream-tool__process-message {
	font-size: 12px;
	color: var(--el-text-color-secondary);
	line-height: 1.45;
	overflow-wrap: anywhere;
}

.stream-tool__process-message small {
	display: block;
	margin-top: 2px;
	color: var(--el-text-color-placeholder);
}
</style>
