<script lang="ts" setup>
import type { FlowKeyType } from '../flowProperties.ts';
import { computed, nextTick, reactive, ref } from 'vue';
import { flowProperties } from '../flowProperties.ts';
import { useElementsInfoStore } from '../stores/elementsInfo.ts';
import { useSelectedInfoStore } from '../stores/selectedInfo.ts';

defineOptions({
  name: 'NextNodePanel',
});
const lf: any = inject('lf');

const elementsInfoStore = useElementsInfoStore();
const selectedInfoStore = useSelectedInfoStore();

const nodeId = ref<string>('');
const graph = computed(() => lf.value.graphModel);
// const node = computed(() => lf.value.node);
const node = computed(() => {
  return lf.value.getNodeModelById(nodeId.value);
});
// console.log('lf.value', lf.value);

// 可见性
const visible = ref(false);

let count = 0;
function addNode(type: FlowKeyType) {
  const newNodeId = `node-${Date.now()}`;
  const baseX = node.value.x + 300;
  let existingNodes: Array<any> = [];
  try {
    existingNodes = graph.value.nodes || [];
  }
  catch (e) {
    existingNodes = [];
  }

  const newWidth = (node.value.width || node.value.w || 200);
  const newHeight = (node.value.height || node.value.h || 40);
  const margin = 20;

  function rectFor(n: any) {
    const w = n.width || n.w || newWidth;
    const h = n.height || n.h || newHeight;
    return {
      left: n.x - w / 2,
      right: n.x + w / 2,
      top: n.y - h / 2,
      bottom: n.y + h / 2,
    };
  }

  function overlap(r1: any, r2: any) {
    return !(r1.right + margin <= r2.left || r1.left - margin >= r2.right || r1.bottom + margin <= r2.top || r1.top - margin >= r2.bottom);
  }

  const existingRects = existingNodes
    .filter((n: any) => n.id !== node.value.id && n.id !== newNodeId)
    .map(rectFor);

  const startY = node.value.y;
  let chosenY = startY + 100 * (count++);
  const step = newHeight + margin;
  let found = false;
  const maxTries = 20;
  for (let i = 0; i < maxTries; i++) {
    const k = Math.floor((i + 1) / 2);
    const candidateY = startY + k * step;
    const newRect = {
      left: baseX - newWidth / 2,
      right: baseX + newWidth / 2,
      top: candidateY - newHeight / 2,
      bottom: candidateY + newHeight / 2,
    };
    let conflict = false;
    for (const r of existingRects) {
      if (overlap(newRect, r)) {
        conflict = true;
        break;
      }
    }
    if (!conflict) {
      chosenY = candidateY;
      found = true;
      break;
    }
  }

  if (!found) {
    chosenY = startY + 100 * count++;
  }

  graph.value.addNode({
    type,
    id: newNodeId,
    x: baseX,
    y: chosenY,
    properties: flowProperties[type],
  });

  const nodeinfo: any = { id: newNodeId, type, title: flowProperties[type].title || '' };
  if (nodeinfo.type === 'user-task-node' || nodeinfo.type === 'normal-task-node') {
    nodeinfo.approveMethod = flowProperties[type].approveMethod;
    nodeinfo.customConfiguration = flowProperties[type].customConfiguration;
  }
  elementsInfoStore.updateElement(newNodeId, nodeinfo);

  const sourceId = nodeId.value;
  const targetId = newNodeId;
  const edgeCandidate = {
    type: 'custom-bezier-edge',
    sourceNodeId: sourceId,
    targetNodeId: targetId,
  };
  graph.value.addEdge(edgeCandidate);

  setTimeout(() => {
    visible.value = false;
    selectedInfoStore.setSelectId(newNodeId);
    selectedInfoStore.setSelectType(type);
    graph.value.edges.forEach((edge: any) => {
      lf.value.setProperties(edge.id, { selected: false });
    });
  }, 100);
}

// Popup 控制：位置
const style = reactive({ left: '0px', top: '0px' });

async function openByAnchor(anchorEl: HTMLElement | null, containerEl: HTMLElement | null, _nodeId: string) {
  nodeId.value = _nodeId;
  if (!anchorEl || !containerEl) {
    return;
  }
  const anchorRect = anchorEl.getBoundingClientRect();
  const containerRect = containerEl.getBoundingClientRect();
  const parentEl = containerEl.parentElement as HTMLElement | null;
  const parentRect = parentEl ? parentEl.getBoundingClientRect() : containerRect;
  const offset = 8;

  // 初始位置相对于 parent（通常为 .page-main）
  let left = anchorRect.right - parentRect.left + offset;
  let top = anchorRect.top - parentRect.top - 4;

  visible.value = true;
  await nextTick();

  const el = (parentEl?.querySelector('.next-node-panel') as HTMLElement) || (document.querySelector('.next-node-panel') as HTMLElement);
  const panelW = el ? el.offsetWidth : 220;
  const panelH = el ? el.offsetHeight : 180;

  const containerLeftRel = containerRect.left - parentRect.left;
  const containerW = containerRect.width;
  const containerH = containerRect.height;

  // 如果超出右侧，则放到左侧（相对于 parent）
  if (left + panelW > containerLeftRel + containerW) {
    left = anchorRect.left - parentRect.left - panelW - offset;
  }
  if (left < containerLeftRel) {
    left = containerLeftRel;
  }

  // 垂直约束落在 container 内
  if (top + panelH > containerH + containerRect.top - parentRect.top) {
    top = Math.max(containerRect.top - parentRect.top, containerRect.top - parentRect.top + containerH - panelH - offset);
  }
  if (top < containerRect.top - parentRect.top) {
    top = containerRect.top - parentRect.top;
  }

  style.left = `${left}px`;
  style.top = `${top}px`;
}

function close() {
  visible.value = false;
}

defineExpose({ openByAnchor, close });
</script>

<template>
  <div
    v-show="visible"
    class="next-node-panel"
    :style="{ position: 'absolute', left: style.left, top: style.top, zIndex: 1000 }"
  >
    <div flex flex-col bg="#fff">
      <div class="node-item" @click="addNode('user-task-node')">
        用户任务
      </div>
      <div class="node-item" @click="addNode('normal-task-node')">
        任务
      </div>
      <div class="node-item" @click="addNode('exclusive-gateway-node')">
        互斥网关
      </div>
      <div class="node-item" @click="addNode('parallel-gateway-node')">
        并行网关
      </div>
      <div class="node-item" @click="addNode('end-node')">
        结束
      </div>
    </div>
  </div>
</template>

<style scoped>
.node-item {
  padding: 5px 15px;
  margin-top: 4px;
  cursor: pointer;
}

.node-item:hover {
  background-color: #f5f5f5;
}

.next-node-panel {
  pointer-events: auto;
  border-radius: 6px;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.12);
}
</style>
