<script setup lang="ts">
import { onBeforeUnmount, onMounted, ref, watch } from "vue";
import MindElixir, { type MindElixirData, type MindElixirInstance } from "mind-elixir";
import "mind-elixir/style.css";

/**
 * mind-elixir 封装：展示/编辑思维导图。
 * 节点着色约定（对比模式）：绿=回忆命中，红=遗漏，蓝=额外。
 */

export interface MindMapTreeNode {
  title: string;
  notes?: string;
  sourceType?: string;
  sourceId?: number;
  children?: MindMapTreeNode[];
}

const props = defineProps<{
  /** 树数据（根节点） */
  tree: MindMapTreeNode | null;
  /** 是否可编辑 */
  editable?: boolean;
  /** 是否按 MATCHED/MISSED 标记着色 */
  colorByCompare?: boolean;
}>();

const emit = defineEmits<{
  /** 编辑模式下结构变化时抛出最新大纲文本 */
  (e: "change", outline: string): void;
  /** 点击带溯源信息的节点 */
  (e: "node-click", node: { sourceType: string; sourceId: number }): void;
}>();

const container = ref<HTMLElement | null>(null);
let instance: MindElixirInstance | null = null;
let nodeCounter = 0;

const COLOR_MATCHED = { background: "#c8e6c9", color: "#1b5e20" };
const COLOR_MISSED = { background: "#ffcdd2", color: "#b71c1c" };

const compareStatus = (notes?: string): "MATCHED" | "MISSED" | null => {
  if (!notes) return null;
  if (notes.startsWith("MATCHED|")) return "MATCHED";
  if (notes.startsWith("MISSED|")) return "MISSED";
  return null;
};

const toElixirNode = (node: MindMapTreeNode): any => {
  nodeCounter += 1;
  const result: any = {
    id: `n${nodeCounter}`,
    topic: node.title || "(未命名)",
    children: (node.children || []).map(toElixirNode),
  };
  if (node.sourceType && node.sourceId != null) {
    result.hyperLink = ""; // 占位，溯源通过 dangerouslySetInnerHTML 外的 tags 展示
    result.tags = [node.sourceType === "REPORT" ? "报告" : node.sourceType === "FRAGMENT" ? "残片" : "应用"];
    result.sourceType = node.sourceType;
    result.sourceId = node.sourceId;
  }
  if (props.colorByCompare) {
    const status = compareStatus(node.notes);
    if (status === "MATCHED") {
      result.style = COLOR_MATCHED;
    } else if (status === "MISSED") {
      result.style = COLOR_MISSED;
    }
  }
  return result;
};

const toElixirData = (tree: MindMapTreeNode): MindElixirData => {
  nodeCounter = 0;
  return {
    nodeData: {
      id: "root",
      topic: tree.title || "思维导图",
      children: (tree.children || []).map(toElixirNode),
    },
  } as MindElixirData;
};

/** 从 mind-elixir 数据导出缩进大纲文本（与后端 MindMapTreeTool.parseOutline 格式一致） */
const toOutline = (): string => {
  if (!instance) return "";
  const data = instance.getData();
  const lines: string[] = [data.nodeData.topic || "思维导图"];
  const walk = (node: any, level: number) => {
    lines.push(`${"  ".repeat(level)}- ${node.topic || ""}`);
    (node.children || []).forEach((c: any) => walk(c, level + 1));
  };
  (data.nodeData.children || []).forEach((c: any) => walk(c, 1));
  return lines.join("\n");
};

defineExpose({ toOutline });

const render = () => {
  if (!container.value || !props.tree) return;
  if (instance) {
    instance.destroy();
    instance = null;
  }
  instance = new MindElixir({
    el: container.value,
    direction: MindElixir.SIDE,
    draggable: !!props.editable,
    editable: !!props.editable,
    contextMenu: !!props.editable,
    toolBar: true,
    keypress: !!props.editable,
  });
  instance.init(toElixirData(props.tree));

  if (props.editable) {
    instance.bus.addListener("operation", () => {
      emit("change", toOutline());
    });
  }

  instance.bus.addListener("selectNewNode", (node: any) => {
    if (node?.sourceType && node?.sourceId != null) {
      emit("node-click", { sourceType: String(node.sourceType), sourceId: Number(node.sourceId) });
    }
  });
};

watch(
  () => [props.tree, props.editable, props.colorByCompare],
  () => render(),
  { deep: false },
);

onMounted(() => render());

onBeforeUnmount(() => {
  if (instance) {
    instance.destroy();
    instance = null;
  }
});
</script>

<template>
  <div class="mind-map-viewer" ref="container"></div>
</template>

<style scoped>
.mind-map-viewer {
  width: 100%;
  height: 480px;
  border: 1px solid var(--border-soft, #e0e0e0);
  border-radius: 8px;
  overflow: hidden;
  background: #fbfefc;
}
</style>
