<script setup lang="ts">
import { computed, ref } from 'vue'
import { Icon } from '@repo/ui'
import { NodeResizer } from '@vue-flow/node-resizer'
import type { OnResize } from '@vue-flow/node-resizer'
import { useElementSize } from '@vueuse/core'
import Canvas from '../../../Canvas.vue'

import type { XYPosition, Connection, CoordinateExtent } from '@vue-flow/core'
import type { CanvasNodeMoveEvent, ConnectStartEvent } from '../../../../Interface'
import { useCanvasNodeContext } from '../../../../hooks/useCanvasNodeContext'
import { useVueFlowContext } from '../../../../hooks/useVueFlowContext'
import { getNodeExecutionStatus } from '../../../../utils/execution-status'

import '@vue-flow/node-resizer/dist/style.css'

defineOptions({
	inheritAttrs: false
})

const node = useCanvasNodeContext()
const { nodeMap, nodes, edges } = useVueFlowContext()

const childrenNodes = computed(
	() => nodes.value.filter((item) => item?.parentId === node.props.value.id) || []
)

const childNodeIds = computed(() => new Set(childrenNodes.value.map((item) => item.id)))
const childrenEdges = computed(() =>
	edges.value.filter(
		(edge) => childNodeIds.value.has(edge.source) && childNodeIds.value.has(edge.target)
	)
)
const emit = defineEmits<{
	update: [attrs: Record<string, unknown>]
	move: [position: XYPosition]
	'add-inner-node': [parentId: string]
	'loop:child:click:node': [id: string, position: XYPosition]
	'loop:child:dblclick:node': [id: string, position: XYPosition]
	'loop:child:click:node:add': [
		payload: { nodeId: string; handle: string; position: XYPosition; event?: MouseEvent }
	]
	'loop:child:create:connection:end': [connection: Connection, event?: MouseEvent]
	'loop:child:update:node:attrs': [id: string, attrs: Record<string, unknown>]
	'loop:child:update:nodes:position': [events: CanvasNodeMoveEvent[]]
	'loop:child:create:connection:cancelled': [
		payload: { handle: ConnectStartEvent; position: XYPosition; event?: MouseEvent }
	]
	'loop:child:run:node': [id: string]
	'loop:child:delete:node': [id: string]
	'loop:child:delete:connection': [connection: Connection]
	'loop:child:click:connection:add': [connection: Connection]
}>()

const nodeData = computed(() => node.props.value.node?.data ?? node.props.value.data)

const nodeType = computed(() => {
	const type = nodeData.value?.nodeType
	return type ? nodeMap.value[type] : undefined
})
const resolvedIcon = computed(() => {
	const icon = `${nodeType.value?.icon || ''}`
	if (!icon) return 'lucide:infinity'
	if (icon.startsWith('data:image/')) return icon
	if (icon.length > 64 && /^[A-Za-z0-9+/=]+$/.test(icon)) {
		return `data:image/png;base64,${icon}`
	}
	return icon
})
const isImageIcon = computed(() => resolvedIcon.value.startsWith('data:image/'))
const isReadOnly = computed(() => node.props.value.readOnly ?? false)

const width = computed(() => Number(nodeData.value?.width) || 424)
const height = computed(() => Number(nodeData.value?.height) || 244)
const executionStatus = computed(() => getNodeExecutionStatus(node.props.value.node))
const innerCanvasRef = ref<HTMLDivElement>()
const { width: innerCanvasWidth, height: innerCanvasHeight } = useElementSize(innerCanvasRef)
const innerCanvasExtent = computed<CoordinateExtent | undefined>(() => {
	if (innerCanvasWidth.value <= 0 || innerCanvasHeight.value <= 0) {
		return undefined
	}

	return [
		[0, 0],
		[Math.max(innerCanvasWidth.value - 1, 0), Math.max(innerCanvasHeight.value - 1, 0)]
	]
})

const nodeClass = computed(() => {
	const classes: string[] = []
	if (node.props.value.selected) {
		classes.push('ring-2', 'ring-#06aed4')
	}
	return classes
})

function onResize(event: OnResize) {
	emit('move', {
		x: event.params.x,
		y: event.params.y
	})
	emit('update', {
		...(event.params.width != null ? { width: event.params.width } : {}),
		...(event.params.height != null ? { height: event.params.height } : {})
	})
}

function onAddNode() {
	if (!isReadOnly.value) {
		emit('add-inner-node', node.props.value.id)
	}
}
</script>

<template>
	<NodeResizer
		:min-width="280"
		:min-height="180"
		:width="width"
		:height="height"
		:is-visible="!isReadOnly && node.props.value.selected"
		handle-class-name="bg-#06aed4! border-white! w-8px h-8px"
		line-class-name="border-#06aed4!"
		@resize="onResize"
	/>

	<div
		:data-execution-status="executionStatus"
		:data-pending="nodeData?.pending ? 'true' : 'false'"
		:class="nodeClass"
		class="canvas-node-status-shell w-full h-full box-border node-loop rounded-12px border-2 border-solid border-#dcdcdc bg-#fff overflow-hidden flex flex-col"
	>
		<!-- 标题栏 -->
		<div
			class="loop-header shrink-0 flex items-center gap-8px pl-12px py-8px border-b border-b-solid border-#e8e8e8 bg-#fff"
		>
			<div
				class="flex-shrink-0 flex items-center justify-center w-8 h-8 rounded-4px"
				:style="{ background: nodeType?.iconColor ?? '#06aed4' }"
			>
				<img
					v-if="isImageIcon"
					:src="resolvedIcon"
					alt="node icon"
					class="w-16px h-16px object-contain"
				/>
				<Icon v-else :icon="resolvedIcon" color="#ffffff" :size="16" />
			</div>
			<span class="text-14px font-medium text-#333">{{
				node.props.value.node?.name ?? '节点标题'
			}}</span>
		</div>

		<!-- 内部画布区域：虚线网格 + 占位内容 -->
		<div class="loop-body flex-1 min-h-0 relative">
			<div
				ref="innerCanvasRef"
				class="absolute top-16px right-16px bottom-16px left-16px z-1 rounded-8px border-1 border-dashed border-#d9d9d9 nodrag nopan overflow-hidden"
				@mousedown.stop
				@click.stop
				@dblclick.stop
			>
				<Canvas
					:id="node.props.value.id"
					:nodes="childrenNodes"
					:edges="childrenEdges"
					:read-only="isReadOnly"
					:node-map="nodeMap"
					:show-control-bar="false"
					:hide-child-node="false"
					:auto-fit="false"
					:max-zoom="1"
					:min-zoom="1"
					:pan-on-drag="false"
					:auto-pan-on-node-drag="false"
					:translate-extent="innerCanvasExtent"
					:node-extent="innerCanvasExtent"
					@click:node="(id, position) => emit('loop:child:click:node', id, position)"
					@dblclick:node="(id, position) => emit('loop:child:dblclick:node', id, position)"
					@click:node:add="emit('loop:child:click:node:add', $event)"
					@create:node="onAddNode"
					@create:connection:end="
						(connection, event) => emit('loop:child:create:connection:end', connection, event)
					"
					@create:connection:cancelled="emit('loop:child:create:connection:cancelled', $event)"
					@update:node:attrs="(id, attrs) => emit('loop:child:update:node:attrs', id, attrs)"
					@update:nodes:position="emit('loop:child:update:nodes:position', $event)"
					@run:node="emit('loop:child:run:node', $event)"
					@delete:node="emit('loop:child:delete:node', $event)"
					@delete:connection="emit('loop:child:delete:connection', $event)"
					@click:connection:add="emit('loop:child:click:connection:add', $event)"
				/>
			</div>
		</div>
	</div>
</template>
