import { store } from '#store/stores.svelte';
import { genShortId } from '#components/utils/IdGen';
import { type Edge, type Node, useSvelteFlow } from '@xyflow/svelte';

import { sanitizeEdge, sanitizeNode } from '#utils/sanitize';

interface ClipboardData {
  tinyflowNodes: Node[];
  tinyflowEdges?: Edge[];
  version: string;
}

/**
 * 对 nodes 数组排序，确保每个父节点出现在其所有子节点之前。
 * 使用 Kahn 算法（拓扑排序）处理任意嵌套层级。
 */
export function sortNodesForSvelteFlow(nodes: Node[]): Node[] {
  const nodeMap = new Map<string, Node>();
  const inDegree = new Map<string, number>(); // 每个节点的“依赖数”（即是否为子节点）
  const childrenMap = new Map<string, string[]>(); // parentId -> childIds

  // 初始化
  for (const node of nodes) {
    nodeMap.set(node.id, node);
    inDegree.set(node.id, 0); // 默认无依赖
    if (node.parentId) {
      // 子节点依赖父节点
      inDegree.set(node.id, 1);
      if (!childrenMap.has(node.parentId)) {
        childrenMap.set(node.parentId, []);
      }
      childrenMap.get(node.parentId)!.push(node.id);
    }
  }

  // 所有根节点（无 parentId 或父不存在）入队
  const queue: Node[] = [];
  for (const node of nodes) {
    if (!node.parentId || !nodeMap.has(node.parentId)) {
      queue.push(node);
    }
  }

  const result: Node[] = [];
  const visited = new Set<string>();

  // BFS 拓扑排序
  while (queue.length > 0) {
    const node = queue.shift()!;
    if (visited.has(node.id)) continue;
    visited.add(node.id);
    result.push(node);

    // 将该节点的所有直接子节点入队（如果其父已处理）
    const children = childrenMap.get(node.id) || [];
    for (const childId of children) {
      if (!visited.has(childId)) {
        queue.push(nodeMap.get(childId)!);
      }
    }
  }

  // 补充可能遗漏的节点（如循环引用或孤立子节点）
  for (const node of nodes) {
    if (!visited.has(node.id)) {
      result.push(node);
    }
  }

  return result;
}

/**
 * 递归遍历对象，仅当遇到 { refType: 'ref', ref: string } 时重写 ref 的 id
 */
function rewriteRefsInData(obj: any, idMap: Map<string, string>): any {
  if (obj === null || obj === undefined) {
    return obj;
  }

  // 如果是数组，递归处理每个元素
  if (Array.isArray(obj)) {
    return obj.map((item) => rewriteRefsInData(item, idMap));
  }

  // 如果是对象，检查是否为引用对象
  if (typeof obj === 'object') {
    // 检查是否是引用定义：refType === 'ref' 且有 ref 字段
    if (obj.refType === 'ref' && typeof obj.ref === 'string') {
      const match = obj.ref.match(/^([^.\s]+)\.(.+)$/);
      if (match) {
        const [_, oldNodeId, paramId] = match;
        const newNodeId = idMap.get(oldNodeId);
        if (newNodeId !== undefined) {
          // 返回新对象，避免修改原数据
          return {
            ...obj,
            ref: `${newNodeId}.${paramId}`,
          };
        }
      }
    }

    // 递归处理所有子属性
    const result: Record<string, any> = {};
    for (const key in obj) {
      if (Object.hasOwn(obj, key)) {
        result[key] = rewriteRefsInData(obj[key], idMap);
      }
    }
    return result;
  }

  // 原始类型（string/number/boolean）直接返回
  return obj;
}

/**
 * 复制粘贴处理器 Hook
 */
export const useCopyPasteHandler = () => {
  const svelteFlow = useSvelteFlow();

  const copyHandler = async (event: ClipboardEvent | KeyboardEvent) => {
    const selectedNodes = store.getNodes().filter((node) => node.selected);
    if (selectedNodes.length === 0) return;

    // 获取完全包含在选中节点之间的边（起点和终点都被选中）
    const allEdges = store.getEdges();
    const relatedEdges = allEdges.filter(
      (edge) =>
        selectedNodes.some((n) => n.id === edge.source) &&
        selectedNodes.some((n) => n.id === edge.target),
    );

    const serializableNodes = selectedNodes.map(sanitizeNode);
    const serializableEdges = relatedEdges.map(sanitizeEdge);

    const clipboardData: ClipboardData = {
      tinyflowNodes: serializableNodes,
      tinyflowEdges: serializableEdges,
      version: '1.0',
    };

    const jsonStr = JSON.stringify(clipboardData, null, 0);

    try {
      // 优先使用 event.clipboardData（在 copy 事件中可用，无需权限）
      if ('clipboardData' in event && event.clipboardData) {
        event.clipboardData.setData('text/plain', jsonStr);
        if (event instanceof ClipboardEvent) {
          event.preventDefault();
        }
      } else {
        // 降级到 navigator.clipboard（需用户手势）
        await navigator.clipboard.writeText(jsonStr);
      }
      console.log('Copied nodes and edges to clipboard');
    } catch (err) {
      console.error('Failed to copy:', err);
      // 可选：同源降级存储
      try {
        sessionStorage.setItem('tinyflow_clipboard', jsonStr);
      } catch {}
    }
  };

  const pasteHandler = (event: ClipboardEvent) => {
    const text = event.clipboardData?.getData('text/plain');
    if (!text) return;

    let parsed: ClipboardData | null = null;
    try {
      parsed = JSON.parse(text);
    } catch {
      return; // 忽略非 JSON 内容
    }

    if (!parsed?.tinyflowNodes || !Array.isArray(parsed.tinyflowNodes)) {
      return;
    }

    event.preventDefault();

    const pastedNodes = sortNodesForSvelteFlow(parsed.tinyflowNodes);
    const pastedEdges = parsed.tinyflowEdges || [];

    // 创建新节点（带新 ID 和偏移）
    const newNodeIdMap = new Map<string, string>();
    const newNodes: Node[] = [];

    for (const node of pastedNodes) {
      const newId = `node_${genShortId()}`;
      newNodeIdMap.set(node.id, newId);
    }

    // 构建新节点（含重写后的 data）
    for (const node of pastedNodes) {
      const newId = newNodeIdMap.get(node.id)!;

      const newParentId =
        node.parentId !== undefined
          ? newNodeIdMap.get(node.parentId) // 安全：即使父不在粘贴范围内，也会是 undefined
          : undefined;

      const newData = rewriteRefsInData(node.data, newNodeIdMap);

      newNodes.push({
        ...node,
        id: newId,
        parentId: newParentId,
        data: newData,
        position: {
          x: (node.position?.x ?? 0) + 50,
          y: (node.position?.y ?? 0) + 50,
        },
        selected: true,
      });
    }

    // 创建新边（仅当两端都在粘贴范围内）
    const newEdges: Edge[] = [];
    for (const edge of pastedEdges) {
      const newSource = newNodeIdMap.get(edge.source);
      const newTarget = newNodeIdMap.get(edge.target);
      if (newSource && newTarget) {
        newEdges.push({
          ...edge,
          id: `edge_${genShortId()}`,
          source: newSource,
          target: newTarget,
        });
      }
    }

    // 更新 store：取消其他节点选中，添加新内容
    store.updateNodes((nodes) => {
      const unselected = nodes.map((n) => ({ ...n, selected: false }));
      return [...unselected, ...newNodes];
    });

    store.updateEdges((edges) => {
      const unselected = edges.map((n) => ({ ...n, selected: false }));
      return [...unselected, ...newEdges];
    });
  };

  return {
    copyHandler,
    pasteHandler,
  };
};
