<script lang="ts" setup>
import { computed, ref, watch } from 'vue'
import { Icon } from '@repo/ui'

import { nodeMap } from '@/nodes'

import { useI18n } from '@/composables/useI18n'
import { getNodeDisplayName } from '@/nodes/i18n'

import type { RunnerNodeState } from '@/store/modules/runner.store'

const props = defineProps<{
	traceNodes: RunnerNodeState[]
}>()

defineEmits<{
	copy: [value: unknown]
}>()

const { t } = useI18n()
const traceExpanded = ref<string[]>([])

watch(
	() => props.traceNodes,
	(nodes) => {
		traceExpanded.value = traceExpanded.value.filter((item) =>
			nodes.some((node) => node.nodeId === item)
		)
	},
	{ deep: true }
)

const nodes = computed(() => props.traceNodes || [])

function statusClass(status?: string | null) {
	if (status === 'success' || status === 'finished') return 'is-success'
	if (status === 'failed' || status === 'error') return 'is-failed'
	if (status === 'running' || status === 'connecting') return 'is-running'
	if (status === 'suspended') return 'is-suspended'
	return 'is-idle'
}

function nodeIcon(node: RunnerNodeState) {
	return nodeMap[node.nodeType]?.icon || 'lucide:circle'
}

function isImageIcon(icon?: string) {
	return !!icon && icon.startsWith('data:image/')
}

function nodeDisplayName(node: RunnerNodeState) {
	if (node.nodeName) return node.nodeName
	return (
		getNodeDisplayName(node.nodeType) ||
		nodeMap[node.nodeType]?.displayName ||
		node.nodeType ||
		t('pages.runWorkflow.tracePanel.unnamedNode')
	)
}

function nodeUseTime(node: RunnerNodeState) {
	const useTime = Number(node.track?.use_time ?? node.track?.useTime ?? 0)
	if (Number.isFinite(useTime) && useTime > 0) {
		return `${useTime} ms`
	}
	return node.lastUpdateTime || '-'
}

function formatDisplayValue(value: unknown) {
	if (value === undefined || value === null || value === '') return ''
	if (typeof value === 'string') return value
	try {
		return JSON.stringify(value, null, 2)
	} catch {
		return String(value)
	}
}
</script>

<template>
	<div class="tab-pane tab-pane--scroll">
		<div v-if="!nodes.length" class="empty-state">
			{{ t('pages.runWorkflow.tracePanel.empty') }}
		</div>
		<el-collapse v-else v-model="traceExpanded" class="trace-list">
			<el-card v-for="node in nodes" :key="node.nodeId">
				<el-collapse-item :name="node.nodeId">
					<template #title>
						<div class="trace-title">
							<div class="trace-title__left">
								<div class="trace-icon">
									<img
										v-if="isImageIcon(nodeIcon(node))"
										:src="nodeIcon(node)"
										alt="node icon"
										class="w-18px h-18px object-contain"
									/>
									<Icon v-else :icon="nodeIcon(node)" :size="18" />
								</div>
								<span class="trace-name">{{ nodeDisplayName(node) }}</span>
							</div>
							<div class="trace-title__right">
								<span class="trace-time">{{ nodeUseTime(node) }}</span>
								<span class="status-dot" :class="statusClass(node.status)"></span>
							</div>
						</div>
					</template>

					<div class="trace-body">
						<div class="panel">
							<div class="section-title">{{ t('pages.runWorkflow.tracePanel.input') }}</div>
							<CodeEditor
								:model-value="formatDisplayValue(node.track?.input_variable) || '-'"
								language="json"
								:tools="true"
								:read-only="true"
								:allow-change-language="false"
								:height="180"
							/>
						</div>

						<div class="panel">
							<div class="section-title">{{ t('pages.runWorkflow.tracePanel.output') }}</div>
							<CodeEditor
								:model-value="formatDisplayValue(node.track?.output_variable) || '-'"
								language="json"
								:tools="true"
								:read-only="true"
								:allow-change-language="false"
								:height="180"
							/>
						</div>
					</div>
				</el-collapse-item>
			</el-card>
		</el-collapse>
	</div>
</template>

<style lang="less" scoped>
.tab-pane {
	height: 100%;
	min-height: 0;
	margin-top: 16px;
}

.tab-pane--scroll {
	padding: 0 16px 16px;
	overflow-y: auto;
}

.empty-state {
	padding: 24px 16px;
	border-radius: 12px;
	background: #f8fafc;
	color: #667085;
	line-height: 1.6;
}

.trace-list {
	border-top: 0;
	display: flex;
	flex-direction: column;
	gap: 8px;
}

.trace-title {
	width: 100%;
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 12px;
	padding-right: 8px;
}

.trace-title__left,
.trace-title__right {
	display: flex;
	align-items: center;
	gap: 10px;
	min-width: 0;
}

.trace-icon {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 28px;
	height: 28px;
	border-radius: 8px;
	background: #eaf2ff;
	color: #296dff;
	flex-shrink: 0;
}

.trace-name {
	color: #344054;
	font-weight: 600;
}

.trace-time {
	color: #667085;
	font-size: 12px;
	white-space: nowrap;
}

.status-dot {
	width: 10px;
	height: 10px;
	border-radius: 999px;
	flex-shrink: 0;
}

.status-dot.is-success {
	background: #12b76a;
}

.status-dot.is-running {
	background: #f79009;
}

.status-dot.is-failed {
	background: #f04438;
}

.status-dot.is-idle {
	background: #98a2b3;
}

.status-dot.is-suspended {
	background: #64748b;
}

.trace-body {
	display: flex;
	flex-direction: column;
	gap: 12px;
	padding-top: 8px;
}

.panel {
	padding: 14px;
	border-radius: 16px;
	background: linear-gradient(180deg, #f8fafc 0%, #f4f7fb 100%);
	border: 1px solid #e4e7ec;
	box-shadow:
		0 8px 24px rgba(15, 23, 42, 0.04),
		inset 0 1px 0 rgba(255, 255, 255, 0.75);

	.section-title {
		margin-right: auto;
		font-size: 14px;
		font-weight: 600;
		color: #344054;
		margin-bottom: 12px;
	}
}

:deep(.el-collapse-item__header) {
	padding: 0;
	height: auto;
	min-height: 54px;
	border: none;
}

:deep(.el-collapse-item__content) {
	padding: 0;
}

:deep(.el-card__body) {
	padding: 4px 8px;
}

:deep(.el-collapse-item__wrap) {
	border: none;
}
</style>
