import { Graph, Cell, Node } from "@antv/x6";

import { StructureType, TopicType } from "./enum";
import { MindMapProjectInfo, TopicItem, HierarchyResult } from "./types";
import Topic from "./components/mindMap/Topic";
import TopicBorder from "./components/mindMap/Border";
import SummaryBorder from "./components/mindMap/SummaryBorder";
import { uuid } from "@repo/utils";
import { hierarchyMethodMap } from "./hierarchy";
import { createEdge } from "./edge";
import { cacluculateExtremeValue, getBorderPositionAndSize } from "./utils";
import { getTheme } from "./theme";
import { topicData, defaultProject } from "./config/data";
import { cloneDeep } from "lodash-es";

type RenderParams = {
  topics: TopicItem[];
  pageSetting: MindMapProjectInfo["pageSetting"];
  structure: StructureType;
  theme: string;
  graph: Graph;
  returnCells?: boolean;
};

// 渲染概要
const createSummaryCells = (
  hierarchyItem: HierarchyResult,
  summary: TopicItem["summary"],
  structure: StructureType,
  pageSetting: MindMapProjectInfo["pageSetting"],
  theme: string,
  graph: Graph,
  offsetX: number,
  offsetY: number
): 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,
        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()) {
    oldCell.setData(node.data, { deep: false });
    oldCell.position(node.position().x, node.position().y);
    oldCell.setSize(node.size().width, node.size().height);
  }
};

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

export const buildTopic = (
  type: TopicType,
  options: Record<string, any> = {},
  parentNode?: Node
): TopicItem => {
  const theme = getTheme(
    "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,
        };
      }
    ),
  };
};

// 获取转换数据
const getConvertData = (
  data: any[],
  parentId: string,
  type: TopicType,
  parentTopic: TopicItem
) => {
  return data.map((item) => {
    const topic = buildTopic(type, { id: item.id, label: item.label }, {
      id: parentId,
      data: parentTopic,
    } as Node);
    topic.parentId = parentId;
    if (item.children) {
      topic.children = getConvertData(
        item.children,
        topic.id,
        TopicType.sub,
        topic
      );
    }

    return topic;
  });
};

/**
 * 根据AI结果创建思维导图
 * @param data
 */
export const getMindmapProjectByAi: (data: any) => MindMapProjectInfo = (data) => {
  const newProject = cloneDeep(defaultProject);
  const mainTopic = buildTopic(TopicType.main, {
    label: "中心主题",
    fill: {
      ...topicData.fill,
      color1: "#30304D",
    },
    text: {
      ...topicData.text,
      fontSize: 30,
      color: "#fff",
    },
  });

  if (Array.isArray(data)) {
    // 获取AI转换数据
    const result = getConvertData(data, "", TopicType.branch, mainTopic);

    mainTopic.children = result;
  }
  newProject.topics = [mainTopic];
  return newProject as MindMapProjectInfo;
};

/**
 * 渲染思维导图项目
 * @param topics 主题数据
 * @param pageSetting 页面设置
 * @param structure 结构类型
 * @param theme 主题
 * @param graph 图形对象
 * @param returnCells 是否返回节点数据
 */
export const renderMindMap = ({
  topics,
  pageSetting,
  structure,
  theme,
  graph,
  returnCells = false,
}: RenderParams) => {
  const 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, parent?: Node) => {
      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,
            // 节点内部执行数据更新方法
          },
          id,
          x: offsetX + x,
          y: offsetY + y,
        });
        // 渲染边框
        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
          );
          cells.push(...(summaryCells || []));
        }
        cells.push(node);
        parent && parent.addChild(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, node);
          });
        }
      }
    };

    traverse(result);
  });
  // 概要节点 返回节点数据
  if (returnCells) {
    return cells;
  }
  const oldCells = graph.getCells();
  // 移除不要的节点及对应的边
  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);
    });
  // 添加所需的节点
  const edgeCells = cells.filter((cell) => cell.isEdge());
  graph.removeCells(edgeCells);
  graph.addCell(edgeCells);
};