<template>
    <div class="curve-container relative w-full h-full overflow-hidden">
        <svg :width="svgWidth" :height="svgHeight">
            <!-- 绘制曲线 -->
            <path
                v-for="(segment, index) in curveSegments"
                :key="index"
                :d="generateCurvePath(segment.startNode, segment.endNode)"
                :stroke="segment.color"
                stroke-width="14"
                stroke-linecap="round"
                fill="none"
            />
            <!-- 绘制节点 -->
            <circle
                v-for="(node, index) in nodes"
                :key="index"
                :cx="node.x"
                :cy="node.y"
                :r="isHovered[index] ? hoverRadius : nodeRadius"
                :fill="isHovered[index] ? hoverFill : nodeFill"
                :stroke="isHovered[index] ? hoverStroke : nodeStroke"
                :stroke-width="isHovered[index] ? hoverStrokeWidth : nodeStrokeWidth"
                :filter="isHovered[index] ? 'drop-shadow(0 0 5px rgba(0,0,0,0.3))' : 'none'"
                @mouseenter="handleNodeMouseEnter(index)"
                @mouseleave="handleNodeMouseLeave(index)"
                @mousedown="startDragging(index, $event)"
                cursor="pointer"
            />
            <!-- 绘制需求池背景 -->
            <rect
                x="20"
                y="80"
                width="140"
                height="220"
                rx="12"
                ry="12"
                fill="#f0f7ff"
                stroke="#aac5e8"
                stroke-width="4"
                opacity="0.9"
                filter="drop-shadow(0 4px 6px rgba(0,0,0,0.1))"
            />
            <rect
                x="700"
                y="80"
                width="120"
                height="220"
                rx="12"
                ry="12"
                fill="#e6f5ef"
                stroke="#98d7c2"
                stroke-width="2"
                opacity="0.9"
                filter="drop-shadow(0 4px 6px rgba(0,0,0,0.1))"
            />
            <!-- 绘制需求池标签 -->
            <text x="80" y="65" text-anchor="middle" font-size="14" fill="#2c6aa0" font-weight="bold">待处理</text>
            <text x="760" y="65" text-anchor="middle" font-size="14" fill="#278865" font-weight="bold">已完成</text>
            <!-- 绘制需求池中的小节点 -->
            <circle
                v-for="(poolNode, index) in poolNodes"
                :key="index"
                :cx="poolNode.isJumping ? poolNode.jumpPosition.x : constrainedPoolNodePosition[index].x"
                :cy="poolNode.isJumping ? poolNode.jumpPosition.y : constrainedPoolNodePosition[index].y + getBounceOffset(index)"
                :r="poolNodeRadius"
                :fill="poolNode.fill"
                :stroke="poolNode.stroke"
                :stroke-width="1.5"
                :filter="
                    poolNode.isJumping
                        ? 'drop-shadow(0 0 8px rgba(0,0,0,0.5))'
                        : poolNode.isHovered
                        ? 'drop-shadow(0 0 6px rgba(0,0,0,0.35))'
                        : 'none'
                "
                @mouseenter="handlePoolNodeMouseEnter(index)"
                @mouseleave="handlePoolNodeMouseLeave(index)"
                cursor="pointer"
            />
            <!-- 需求池装饰元素 -->
            <g v-if="!isMobileView">
                <path d="M30,80 L30,300" stroke="#aac5e8" stroke-width="1" stroke-dasharray="5,5" opacity="0.5" />
                <path d="M110,80 L110,300" stroke="#aac5e8" stroke-width="1" stroke-dasharray="5,5" opacity="0.5" />
                <path d="M710,80 L710,300" stroke="#98d7c2" stroke-width="1" stroke-dasharray="5,5" opacity="0.5" />
                <path d="M790,80 L790,300" stroke="#98d7c2" stroke-width="1" stroke-dasharray="5,5" opacity="0.5" />
            </g>
        </svg>
    </div>
</template>

<script setup>
import { ref, reactive, onMounted, onUnmounted } from "vue";

const svgWidth = ref(800);
const svgHeight = ref(400);

// 节点样式配置
const nodeRadius = ref(8);
const hoverRadius = ref(12);
const nodeFill = ref("#fff");
const hoverFill = ref("#e8f4ff");
const nodeStroke = ref("#3498db");
const hoverStroke = ref("#2980b9");
const nodeStrokeWidth = ref(2.5);
const hoverStrokeWidth = ref(3.5);

// 需求池节点样式配置
const poolNodeRadius = ref(6);

// 节点数据
const nodes = ref([
    { x: 150, y: 220 },
    { x: 350, y: 180 },
    { x: 550, y: 250 },
    { x: 750, y: 220 }
]);

// 曲线分段信息
const curveSegments = ref([
    { startNode: 0, endNode: 1, color: "#3498db" },
    { startNode: 1, endNode: 2, color: "#2ecc71" },
    { startNode: 2, endNode: 3, color: "#3498db" }
]);

// 需求池节点数据
const poolNodes = ref([
    { poolIndex: 0, fill: "#3498db", stroke: "#2980b9", isHovered: false, isJumping: false },
    { poolIndex: 0, fill: "#e74c3c", stroke: "#c0392b", isHovered: false, isJumping: false },
    { poolIndex: 0, fill: "#9b59b6", stroke: "#8e44ad", isHovered: false, isJumping: false },
    { poolIndex: 0, fill: "#e67e22", stroke: "#d35400", isHovered: false, isJumping: false },
    { poolIndex: 0, fill: "#f1c40f", stroke: "#f39c12", isHovered: false, isJumping: false },
    { poolIndex: 0, fill: "#1abc9c", stroke: "#16a085", isHovered: false, isJumping: false },
    { poolIndex: 0, fill: "#3498db", stroke: "#2980b9", isHovered: false, isJumping: false },
    { poolIndex: 0, fill: "#e74c3c", stroke: "#c0392b", isHovered: false, isJumping: false },
    { poolIndex: 1, fill: "#1abc9c", stroke: "#16a085", isHovered: false, isJumping: false },
    { poolIndex: 1, fill: "#3498db", stroke: "#2980b9", isHovered: false, isJumping: false },
    { poolIndex: 1, fill: "#95a5a6", stroke: "#7f8c8d", isHovered: false, isJumping: false }
]);

// 跟踪鼠标悬停状态
const isHovered = reactive(nodes.value.map(() => false));

// 响应式视图标志
const isMobileView = ref(false);

// 动画相关
const bounceOffsets = ref(poolNodes.value.map(() => 0));
let animationFrameId = null;
let lastTime = 0;
let jumpTimer = null;

// 存储约束后的节点位置（避免超出需求池）
const constrainedPoolNodePosition = ref(poolNodes.value.map(() => ({ x: 0, y: 0 })));

// 获取需求池节点位置（带边界约束）
const getPoolNodePosition = (poolIndex, nodeIndex) => {
    const poolX = poolIndex === 0 ? 80 : 760;
    const poolY = 100;
    const nodesPerColumn = 4;
    const column = Math.floor(nodeIndex / nodesPerColumn);
    const row = nodeIndex % nodesPerColumn;
    const spacingX = 25;
    const spacingY = 25;

    // 基础位置计算
    let baseX = poolX + (column - 1) * spacingX;
    let baseY = poolY + row * spacingY;

    // 需求池边界（考虑节点半径）
    const nodeRadius = poolNodeRadius.value;
    const poolLeft = poolIndex === 0 ? 20 + nodeRadius : 700 + nodeRadius;
    const poolRight = poolIndex === 0 ? 20 + 120 - nodeRadius : 700 + 120 - nodeRadius;
    const poolTop = 80 + nodeRadius;
    const poolBottom = 80 + 220 - nodeRadius;

    // 边界约束逻辑
    const constrainedX = Math.max(poolLeft, Math.min(baseX, poolRight));
    const constrainedY = Math.max(poolTop, Math.min(baseY, poolBottom));

    return { x: constrainedX, y: constrainedY };
};

// 获取节点跳动偏移量
const getBounceOffset = index => {
    return bounceOffsets.value[index];
};

// 动态生成曲线路径
const generateCurvePath = (startNodeIndex, endNodeIndex) => {
    const start = nodes.value[startNodeIndex];
    const end = nodes.value[endNodeIndex];

    const dx = end.x - start.x;
    const dy = end.y - start.y;
    const controlDistance = Math.max(Math.abs(dx), Math.abs(dy)) * 0.3;

    const cp1x = start.x + dx * 0.3;
    const cp1y = start.y + dy * 0.2 - controlDistance;
    const cp2x = start.x + dx * 0.7;
    const cp2y = start.y + dy * 0.8 + controlDistance;

    return `M${start.x},${start.y} C${cp1x},${cp1y} ${cp2x},${cp2y} ${end.x},${end.y}`;
};

// 处理节点鼠标事件
const handleNodeMouseEnter = index => {
    isHovered[index] = true;
};

const handleNodeMouseLeave = index => {
    isHovered[index] = false;
};

// 处理需求池节点鼠标事件
const handlePoolNodeMouseEnter = index => {
    poolNodes.value[index].isHovered = true;
};

const handlePoolNodeMouseLeave = index => {
    poolNodes.value[index].isHovered = false;
};

// 开始节点自动跳入曲线
const startAutoJumping = () => {
    const minInterval = 3000;
    const maxInterval = 5000;

    const jumpRandomNode = () => {
        const leftPoolNodes = poolNodes.value.filter(node => node.poolIndex === 0 && !node.isJumping);

        if (leftPoolNodes.length > 0) {
            const randomIndex = Math.floor(Math.random() * leftPoolNodes.length);
            const nodeToJump = leftPoolNodes[randomIndex];
            const poolNodeIndex = poolNodes.value.indexOf(nodeToJump);

            jumpNodeToCurve(poolNodeIndex);
        }

        jumpTimer = setTimeout(jumpRandomNode, Math.random() * (maxInterval - minInterval) + minInterval);
    };

    jumpTimer = setTimeout(jumpRandomNode, Math.random() * (maxInterval - minInterval) + minInterval);
};

// 节点跳入曲线动画
const jumpNodeToCurve = poolNodeIndex => {
    const poolNode = poolNodes.value[poolNodeIndex];
    if (poolNode.isJumping) return;

    const targetNodeIndex = Math.floor(Math.random() * nodes.value.length);
    const targetNode = nodes.value[targetNodeIndex];

    const startPos = getPoolNodePosition(poolNode.poolIndex, poolNodeIndex);
    startPos.y += getBounceOffset(poolNodeIndex);

    poolNode.isJumping = true;
    poolNode.jumpPosition = { ...startPos };
    poolNode.jumpProgress = 0;
    poolNode.targetNodeIndex = targetNodeIndex;

    const startTime = Date.now();
    const duration = 1500;

    const animateJump = () => {
        if (!poolNode.isJumping) return;

        const elapsed = Date.now() - startTime;
        const progress = Math.min(elapsed / duration, 1);

        const easeOutCubic = t => 1 - Math.pow(1 - t, 3);
        const easedProgress = easeOutCubic(progress);

        poolNode.jumpPosition.x = startPos.x + (targetNode.x - startPos.x) * easedProgress;
        poolNode.jumpPosition.y = startPos.y + (targetNode.y - startPos.y) * easedProgress;

        if (progress < 1) {
            requestAnimationFrame(animateJump);
        } else {
            completeNodeJump(poolNodeIndex);
        }
    };

    requestAnimationFrame(animateJump);
};

// 完成节点跳跃并添加到曲线上
const completeNodeJump = poolNodeIndex => {
    const poolNode = poolNodes.value[poolNodeIndex];

    const newNode = { ...poolNode.jumpPosition };
    nodes.value.push(newNode);
    const newNodeIndex = nodes.value.length - 1;

    const targetNodeIndex = poolNode.targetNodeIndex;
    const segmentIndex = findSegmentContainingNode(targetNodeIndex);

    if (segmentIndex !== -1) {
        const segment = curveSegments.value[segmentIndex];
        if (segment.startNode === targetNodeIndex) {
            curveSegments.value.push({
                startNode: newNodeIndex,
                endNode: segment.endNode,
                color: segment.color
            });
            segment.endNode = newNodeIndex;
        } else if (segment.endNode === targetNodeIndex) {
            curveSegments.value.push({
                startNode: segment.startNode,
                endNode: newNodeIndex,
                color: segment.color
            });
            segment.startNode = newNodeIndex;
        }
    }

    poolNodes.value.splice(poolNodeIndex, 1);
    bounceOffsets.value = poolNodes.value.map(() => 0);

    setTimeout(() => {
        addNewPoolNode();
    }, 1000);
};

// 添加新的需求池节点
const addNewPoolNode = () => {
    const colors = [
        { fill: "#3498db", stroke: "#2980b9" },
        { fill: "#e74c3c", stroke: "#c0392b" },
        { fill: "#9b59b6", stroke: "#8e44ad" },
        { fill: "#e67e22", stroke: "#d35400" },
        { fill: "#f1c40f", stroke: "#f39c12" },
        { fill: "#1abc9c", stroke: "#16a085" },
        { fill: "#95a5a6", stroke: "#7f8c8d" },
        { fill: "#3498db", stroke: "#2980b9" },
        { fill: "#e74c3c", stroke: "#c0392b" },
        { fill: "#9b59b6", stroke: "#8e44ad" }
    ];

    const randomColor = colors[Math.floor(Math.random() * colors.length)];

    poolNodes.value.push({
        poolIndex: 0,
        ...randomColor,
        isHovered: false,
        isJumping: false
    });

    updateConstrainedPositions(); // 新增节点后更新约束位置
};

// 找到包含指定节点的线段
const findSegmentContainingNode = nodeIndex => {
    return curveSegments.value.findIndex(segment => segment.startNode === nodeIndex || segment.endNode === nodeIndex);
};

// 更新所有需求池节点的约束位置
const updateConstrainedPositions = () => {
    constrainedPoolNodePosition.value = poolNodes.value.map((node, index) => getPoolNodePosition(node.poolIndex, index));
};

// 动画函数
const animate = time => {
    if (!lastTime) lastTime = time;

    poolNodes.value.forEach((_, index) => {
        if (!poolNodes.value[index].isJumping) {
            const frequency = 0.0025 * (index + 1);
            const amplitude = 2.5;
            bounceOffsets.value[index] = amplitude * Math.sin(time * frequency);
        }
    });

    lastTime = time;
    animationFrameId = requestAnimationFrame(animate);
};

// 生命周期钩子
onMounted(() => {
    updateConstrainedPositions(); // 初始化约束位置
    animationFrameId = requestAnimationFrame(animate);
    startAutoJumping();

    const handleResize = () => {
        isMobileView.value = window.innerWidth < 768;
        updateConstrainedPositions(); // 窗口大小变化时更新约束位置
    };

    window.addEventListener("resize", handleResize);
    handleResize();
});

onUnmounted(() => {
    if (animationFrameId) {
        cancelAnimationFrame(animationFrameId);
    }

    if (jumpTimer) {
        clearTimeout(jumpTimer);
    }

    window.removeEventListener("resize", handleResize);
});
</script>

<style scoped>
.curve-container {
    width: 100%;
    height: 100%;
}
</style>
