import { StructureType, TopicType } from "@/enum";
import { MindMapProjectInfo, TopicItem, HierarchyResult } from "@/types";
import { Graph, Cell, Node } from "@antv/x6";
import Topic from "@/components/mindMap/Topic";
import TopicBorder from "@/components/mindMap/Border";
import SummaryBorder from "@/components/mindMap/SummaryBorder";
import { topicData } from "@/config/data";
import { uuid } from "@repo/utils";
import { hierarchyMethodMap } from "./hierarchy";
import { createEdge } from "./edge";
import { getTheme } from "./theme";
import { topicMenu } from "@/utils/contentMenu";
import {
  cacluculateExtremeValue,
  getBorderPositionAndSize,
} from "../mindmapHander";
import { useMindMapStore } from "../models/mindMapModel";
import { cloneDeep } from "lodash-es";

type RenderParams = {
  topics: TopicItem[];
  pageSetting: MindMapProjectInfo["pageSetting"];
  structure: StructureType;
  theme: string;
  graph: Graph;
  setMindProjectInfo?: (data: any) => void;
  returnCells?: boolean;
  showTool?: boolean;
};

/**
 * 渲染思维导图项目
 * @param graph
 */
export const renderMindMap = ({
  topics,
  pageSetting,
  structure,
  theme,
  graph,
  setMindProjectInfo,
  returnCells = false,
  showTool = true,
}: RenderParams) => {
  let cells: Cell[] = [];
  topics.forEach((topic) => {
    // 遍历出层次结构
    const result: HierarchyResult = hierarchyMethodMap[structure]?.(
      topic,
      pageSetting
    );
    let originPosition = { x: topic?.x ?? -10, y: topic?.y ?? -10 };
    // if (graph.hasCell(topic.id) && !topic.isSummary) {
    //   const node = graph.getCellById(topic.id);
    //   if (node.isNode()) {
    //     originPosition = node.position();
    //   }
    // }
    const offsetX = originPosition.x - result.x;
    const offsetY = originPosition.y - result.y;
    const traverse = (hierarchyItem: HierarchyResult) => {
      if (hierarchyItem) {
        const { data, children, x, y } = hierarchyItem;
        const id = data?.id || uuid();
        // 创建主题节点
        const node = graph.createNode({
          ...Topic,
          width: data.width,
          height: data.height,
          data: {
            ...data,
            opacity: 100,
            // 节点内部执行数据更新方法
            setMindProjectInfo,
          },
          id,
          x: offsetX + x,
          y: offsetY + y,
          tools: showTool
            ? [
                {
                  name: "contextmenu",
                  args: {
                    menu: topicMenu,
                  },
                },
              ]
            : [],
        });
        // 渲染边框
        if (data.border) {
          cells.push(
            createBorderComponent(hierarchyItem, offsetX, offsetY, graph)
          );
        }
        // 渲染概要
        if (data.summary) {
          const summaryCells = createSummaryCells(
            hierarchyItem,
            data.summary,
            structure,
            pageSetting,
            theme,
            graph,
            offsetX,
            offsetY,
            setMindProjectInfo
          );
          cells.push(...(summaryCells || []));
        }
        cells.push(node);
        if (data?.links) {
          cells.push(...data.links.map((item) => graph.createEdge(item)));
        }

        if (children) {
          children.forEach((item: HierarchyResult, index) => {
            const isBracket = [
              StructureType.leftBracket,
              StructureType.rightBracket,
            ].includes(structure);
            // 括号图不绘制中间连线
            if (!isBracket || index === 0 || index === children.length - 1) {
              const edge = createEdge(graph, id, item, structure, theme, {
                onlyOneChild: children.length === 1,
                direction: item?.direction,
              });
              cells.push(edge);
              node.addChild(edge);
            }
            // 递归遍历
            traverse(item);
          });
        }
      }
    };

    traverse(result);
  });

  // 根据id去重
  cells = cells.filter(
    (item, index, arr) => arr.findIndex((i) => i.id === item.id) === index
  );

  // 数据为概要节点 返回节点数据
  if (returnCells) {
    return cells;
  }

  const oldCells = graph.getCells();

  console.log("oldCells", oldCells, cells);
  // 移除不要的节点及对应的边
  oldCells.forEach((cell) => {
    if (!cells.find((item) => cell.id === item.id)) {
      graph.removeCell(cell.id + "-edge");
      graph.removeCell(cell);
    }
  });

  // 添加节点
  cells
    .filter((cell) => cell.isNode() && !graph.hasCell(cell.id))
    .forEach((cell) => {
      graph.addCell(cell);
    });

  // 更新老的节点
  cells
    .filter((cell) => cell.isNode() && graph.hasCell(cell.id))
    .forEach((cell) => {
      cell.isNode() && updateNode(cell, graph);
    });

  // 处理父子节点关系
  cells.forEach((cell) => {
    const data = cell.getData();
    if (data?.parentId) {
      const parent = graph.getCellById(data.parentId);
      const child = graph.getCellById(cell.id);
      if (parent && child && !child.hasParent()) {
        parent.removeChild(child);
        parent.addChild(child);
      }
    }
  });

  // 添加所需的节点
  const edgeCells = cells.filter((cell) => cell.isEdge());
  graph.removeCells(edgeCells);
  graph.addCell(edgeCells);
};

// 渲染概要
const createSummaryCells = (
  hierarchyItem: HierarchyResult,
  summary: TopicItem["summary"],
  structure: StructureType,
  pageSetting: MindMapProjectInfo["pageSetting"],
  theme: string,
  graph: Graph,
  offsetX: number,
  offsetY: number,
  setMindProjectInfo?: (data: any) => void
): Cell[] => {
  let cells: Cell[] = [];
  if (summary) {
    const positionAndSize = cacluculateExtremeValue(
      hierarchyItem,
      hierarchyItem.children
    );
    const totalHeight = positionAndSize.maxY - positionAndSize.minY;
    const totalWidth = positionAndSize.maxX - positionAndSize.minX;

    // 概要边框
    const node = graph.createNode({
      ...SummaryBorder,
      data: summary.border,
      id: summary.topic.id + "-border",
      zIndex: 0,
      position: {
        x: offsetX + positionAndSize.minX - 2,
        y: offsetY + positionAndSize.minY - 2,
      },
      size: {
        width: totalWidth + 4,
        height: totalHeight + 4,
      },
    });
    cells.push(node);

    let position = {
      x: offsetX + hierarchyItem.x + totalWidth + 40,
      y: offsetY + hierarchyItem.y,
    };

    if (
      [
        StructureType.left,
        StructureType.leftBracket,
        StructureType.leftFishbone,
        StructureType.leftTreeShape,
      ].includes(structure) ||
      (structure === StructureType.leftRight &&
        hierarchyItem.direction === "left")
    ) {
      position = {
        x: offsetX + hierarchyItem.x - 40 - totalWidth,
        y: offsetY + hierarchyItem.y,
      };
    }
    const list =
      renderMindMap({
        topics: [
          {
            ...summary.topic,
            ...position,
          },
        ],
        pageSetting,
        structure,
        theme,
        graph,
        setMindProjectInfo,
        returnCells: true,
      }) || [];

    // 概要节点
    cells.push(...list);
  }
  return cells;
};

// 创建外框组件
const createBorderComponent = (
  hierarchyItem: HierarchyResult,
  offsetX: number,
  offsetY: number,
  graph: Graph
) => {
  const positionAndSize = getBorderPositionAndSize(hierarchyItem);
  return graph.createNode({
    ...TopicBorder,
    id: hierarchyItem.id + "-border",
    data: {
      ...hierarchyItem.data.border,
      origin: hierarchyItem.id,
    },
    zIndex: 0,
    position: {
      x: offsetX + positionAndSize.x,
      y: offsetY + positionAndSize.y,
    },
    size: {
      width: positionAndSize.width,
      height: positionAndSize.height,
    },
  });
};

// 更新现有节点 优化点
const updateNode = (node: Node, graph: Graph) => {
  const oldCell = graph.getCellById(node.id);
  if (oldCell.isNode()) {
    const { width, height } = node.size();
    oldCell.setData(node.data, { silent: false, deep: false });
    const p = node.position();
    oldCell.setPosition(p);
    oldCell.setSize(width, height);
  }
};

/**
 * 添加分支主题
 */
export const addTopic = (
  type: TopicType,
  setMindProjectInfo: (data: any) => void,
  graph: Graph,
  parentNode?: Node,
  otherData: Record<string, any> = {}
): TopicItem | undefined => {
  const projectInfo: MindMapProjectInfo = cloneDeep(
    useMindMapStore.getState().mindProjectInfo
  );
  if (!projectInfo || !setMindProjectInfo) return;
  // 构造主题节点
  const topic = buildTopic(
    type,
    {
      ...(otherData || {}),
      parentId: parentNode?.id,
      isSummary: parentNode?.data?.isSummary,
      summarySource: parentNode?.data?.summarySource,
    },
    graph,
    parentNode
  );

  // 往父级节点添加子节点
  if (parentNode) {
    const parentId = parentNode.id;
    const traverse = (topics: TopicItem[]) => {
      topics.forEach((item) => {
        if (item.id === parentId) {
          item.collapsed = false; // 展开父节点
          if (item.children) {
            item.children?.push(topic);
          } else {
            item.children = [topic];
          }
        } else if (item.children) {
          traverse(item.children);
        }
        if (item.summary) {
          traverse([item.summary.topic]);
        }
      });
    };

    traverse(projectInfo?.topics || []);
  } else {
    projectInfo.topics.push(topic);
  }

  setMindProjectInfo({ info: projectInfo });
  // 进入编辑模式
  if (parentNode) {
    setTimeout(() => {
      const newTopicNode = graph.getCellById(topic.id);
      if (newTopicNode) {
        newTopicNode.prop("customEdit", true);
      }
    }, 50);
  }
  return topic;
};

const topicMap = {
  [TopicType.main]: {
    label: "中心主题",
    width: 176,
    height: 65,
  },
  [TopicType.branch]: {
    label: "分支主题",
    width: 104,
    height: 40,
  },
  [TopicType.sub]: {
    label: "子主题",
    width: 54,
    height: 26,
  },
};

/**
 * 构建一个主题数据
 * @param type 主题类型
 * @param options 配置项
 * @param graph 图形实例
 * @param parentNode 父节点
 * @returns
 */
export const buildTopic = (
  type: TopicType,
  options: Record<string, any> = {},
  graph?: Graph,
  parentNode?: Node
): TopicItem => {
  const projectInfo: MindMapProjectInfo = cloneDeep(
    useMindMapStore.getState().mindProjectInfo
  );

  const theme = getTheme(
    projectInfo?.theme || "default",
    type === TopicType.sub ? parentNode?.data : undefined
  );
  const id = uuid();
  return {
    ...topicData,
    id,
    type,
    label: topicMap[type].label || "自由主题",
    width: topicMap[type].width || 206,
    height: topicMap[type].height || 70,
    fill: {
      ...topicData.fill,
      ...theme[type]?.fill,
    },
    text: {
      ...topicData.text,
      ...theme[type]?.text,
    },
    stroke: {
      ...topicData.stroke,
      ...theme[type]?.stroke,
    },
    edge: {
      ...topicData.edge,
      color: theme[type]?.edge.color,
    },
    ...options,
    children: (options?.children || topicData.children || []).map(
      (item: TopicItem) => {
        return {
          ...item,
          parentId: id,
        };
      }
    ),
  };
};

/**
 * 更新主题数据
 * @param id 主题id
 * @param value 更新的数据
 */
export const updateTopic = (
  id: string,
  value: Partial<TopicItem>,
  setMindProjectInfo: (data: any) => void
) => {
  const projectInfo = cloneDeep(useMindMapStore.getState().mindProjectInfo);
  if (!projectInfo || !setMindProjectInfo) return;

  const traverse = (topics: TopicItem[]) => {
    topics.forEach((item) => {
      if (item.id === id) {
        Object.assign(item, value);
      }
      if (item.children) {
        traverse(item.children);
      }
    });
  };

  traverse(projectInfo?.topics || []);
  setMindProjectInfo({ info: projectInfo });
};

/**
 * 根据ai数据返回思维导图主题
 * @param data
 * @param parentId
 * @param type
 * @param parentTopic
 * @param graph
 * @returns
 */
export const getTopicsByAiData = (
  data: any[],
  parentId: string,
  type: TopicType,
  parentTopic: TopicItem,
  graph?: Graph
) => {
  const ids: string[] = [];
  data = Array.isArray(data) ? data : [data];
  const topics = data?.map((item) => {
    const topic = buildTopic(type, { id: item.id, label: item.label }, graph, {
      id: parentId,
      data: parentTopic,
    } as Node);
    topic.parentId = parentId;
    ids.push(topic.id);
    if (item.children) {
      const child = getTopicsByAiData(
        item.children,
        topic.id,
        TopicType.sub,
        topic,
        graph
      );
      topic.children = child.topics;
      ids.push(...child.ids);
    }

    return topic;
  });

  return {
    topics,
    ids,
  };
};
