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

import { nodes, type INodeType } from '@/nodes'
import { getNodeDescription, getNodeDisplayName } from '@/nodes/i18n'
import { useI18n } from '@/composables/useI18n'

defineOptions({
	name: 'AddMaterialsPop'
})

interface NodeItem {
	id: string
	type: string
	name: string
	description?: string
	icon?: string
	isImageIcon?: boolean
	iconColor?: string
	raw: INodeType
}

interface NodeGroup {
	id: string
	label: string
	nodes: NodeItem[]
}

type NodeLibraryGroupId = 'start' | 'logic' | 'data' | 'other' | 'tool' | 'custom'

const props = defineProps<{
	hideStart?: boolean
	parentNodeType?: string
	ignoreDrag?: boolean
}>()

const emit = defineEmits<{
	'add-node': [value: { type: string }]
}>()

const { onDragStart } = useDragAndDrop()
const { t } = useI18n()

const GROUP_ALIASES: Record<string, NodeLibraryGroupId> = {
	start: 'start',
	logic: 'logic',
	data: 'data',
	tool: 'tool',
	other: 'other',
	custom: 'custom'
}

const groupLabels = computed(() => ({
	start: t('pages.nodeLibrary.groups.start'),
	data: t('pages.nodeLibrary.groups.data'),
	logic: t('pages.nodeLibrary.groups.logic'),
	tool: t('pages.nodeLibrary.groups.tool'),
	other: t('pages.nodeLibrary.groups.other'),
	custom: t('pages.nodeLibrary.groups.custom')
}))

const GROUP_ORDER: NodeLibraryGroupId[] = ['start', 'data', 'logic', 'tool', 'other', 'custom']

const canAddNodeType = (nodeType: string) => {
	const isLoopContainer = ['loop', 'iteration'].includes(props.parentNodeType || '')

	if (nodeType === 'loop-end') {
		return isLoopContainer
	}

	if (isLoopContainer && ['loop', 'iteration'].includes(nodeType)) {
		return false
	}

	return true
}

const getGroupId = (group?: string): NodeLibraryGroupId => GROUP_ALIASES[group || ''] || 'other'
const isImageIcon = (icon?: string) => !!icon && icon.startsWith('data:image/')

const materials = computed<NodeGroup[]>(() => {
	const groupMap = new Map<string, NodeGroup>()

	nodes
		.filter((node) => {
			return (
				!node.hideInLibary &&
				(getGroupId(node.group) !== 'start' || !props.hideStart) &&
				canAddNodeType(node.schema.nodeType)
			)
		})
		.forEach((node) => {
			const groupId = getGroupId(node.group)
			const groupLabel = groupLabels.value[groupId]

			if (!groupMap.has(groupId)) {
				groupMap.set(groupId, {
					id: groupId,
					label: groupLabel,
					nodes: []
				})
			}

			groupMap.get(groupId)!.nodes.push({
				id: node.name,
				type: node.schema.nodeType,
				name: node.displayName,
				description: getNodeDescription(node.schema.nodeType),
				icon: node.icon,
				isImageIcon: isImageIcon(node.icon),
				iconColor: node.iconColor,
				raw: node
			})
		})

	return GROUP_ORDER.filter((groupId) => groupMap.has(groupId)).map(
		(groupId) => groupMap.get(groupId)!
	)
})

const activeGroup = ref('')

watch(
	materials,
	(groups) => {
		if (!groups.length) return
		if (!activeGroup.value || !groups.some((group) => group.id === activeGroup.value)) {
			activeGroup.value = groups[0]!.id
		}
	},
	{ immediate: true }
)

const onAddNode = (value: NodeItem) => {
	emit('add-node', { type: value.type })
}
</script>

<template>
	<div class="node-lib">
		<el-tabs v-model="activeGroup" class="node-tabs" stretch>
			<el-tab-pane v-for="group in materials" :key="group.id" :label="group.label" :name="group.id">
				<ul>
					<li
						v-for="item in group.nodes"
						:key="item.id"
						class="tool mb-3 flex items-center"
						:draggable="!props.ignoreDrag"
						@click="onAddNode(item)"
						@dragstart="onDragStart($event, item.type)"
					>
						<div
							class="mr-2 p-1 rounded flex items-center justify-center"
							:style="{ backgroundColor: item.iconColor || '#6172f3' }"
						>
							<img
								v-if="item.isImageIcon"
								:src="item.icon"
								alt="node icon"
								class="w-16px h-16px object-contain"
							/>
							<Icon
								v-else
								:icon="item.icon || 'lucide:square'"
								height="16"
								width="16"
								color="#fff"
							/>
						</div>
						<div class="flex flex-col">
							<span>{{ item.name }}</span>
							<span v-if="item.description" class="desc">{{ item.description }}</span>
							<span v-if="item.raw?.author" class="desc">作者: {{ item.raw?.author }}</span>
						</div>
					</li>
				</ul>
			</el-tab-pane>
		</el-tabs>
	</div>
</template>

<style lang="less" scoped>
.node-lib {
	min-width: 220px;
}

.node-tabs {
	:deep(.el-tabs__header) {
		margin-bottom: 8px;
	}
}

ul {
	padding: 0 0 0 10px;

	.tool {
		list-style: none;
		cursor: pointer;

		span {
			color: #354052;
		}

		.desc {
			font-size: 12px;
			color: #9ca3af;
		}

		&:hover {
			span {
				color: #6172f3;
			}
		}
	}
}
</style>
