export type MindMapData = {
  data: Record<string, unknown>;
  children?: unknown[];
};

export type MindmapRouteMeta = {
  requestId?: string;
  traceId?: string;
  workspaceId?: string | null;
  documentId?: string;
  pageId?: string;
  mindmapId?: string;
  attachmentId?: string;
  updatedAt?: string | null;
};

export type MindmapProjectionNode = {
  uid: string;
  text: string;
  depth: number;
  childCount: number;
};

export type MindmapProjection = {
  projectionId: string;
  projection: "mindmap_subtree";
  documentId: string;
  mindmapId: string;
  rootNodeId: string | null;
  title: string;
  nodeCount: number;
  nodes: MindmapProjectionNode[];
  data: MindMapData;
  meta: MindmapRouteMeta | null;
};

export const defaultMindmapData: MindMapData = {
  data: { text: "中心主题" },
  children: [],
};

const isRecord = (value: unknown): value is Record<string, unknown> =>
  typeof value === "object" && value !== null && !Array.isArray(value);

// simple-mind-map 在文本字段缺失时会直接崩溃，这里统一做兜底归一化。
export const normalizeMindmapData = (input: unknown): unknown => {
  if (!input || typeof input !== "object") return defaultMindmapData;
  const root = (input as { root?: unknown }).root ?? input;

  const walk = (node: unknown) => {
    if (!isRecord(node)) return;
    if (!isRecord(node.data)) {
      node.data = {};
    }
    const rawText = node.data.text;
    node.data.text = typeof rawText === "string" ? rawText : String(rawText ?? "");

    const gen = node.data.generalization;
    const fixGen = (value: unknown) => {
      if (!isRecord(value)) return;
      const text = value.text;
      value.text = typeof text === "string" ? text : String(text ?? "");
    };

    if (Array.isArray(gen)) gen.forEach(fixGen);
    else fixGen(gen);

    if (Array.isArray(node.children)) {
      node.children.forEach(walk);
    }
  };

  walk(root);
  return input;
};

// 持久化/初始化统一使用根节点对象，避免 wrapper 误传给 simple-mind-map。
export const canonicalizeMindmapData = (input: unknown): MindMapData => {
  const normalized = (normalizeMindmapData(input) ?? defaultMindmapData) as Record<string, unknown>;
  const root =
    normalized && typeof normalized === "object" && "root" in normalized
      ? normalized.root
      : normalized;
  return (normalizeMindmapData(root) ?? defaultMindmapData) as MindMapData;
};

export const extractMindmapTitle = (input: unknown): string => {
  const canonical = canonicalizeMindmapData(input);
  const text = canonical?.data?.text;
  if (typeof text === "string" && text.trim()) {
    return text.trim();
  }
  return "未命名导图";
};

export const summarizeMindmapProjectionNodes = (input: unknown): MindmapProjectionNode[] => {
  const root = canonicalizeMindmapData(input);
  const queue: Array<{ node: MindMapData; depth: number }> = [{ node: root, depth: 0 }];
  const nodes: MindmapProjectionNode[] = [];

  while (queue.length > 0) {
    const current = queue.shift();
    if (!current) break;
    const uidRaw = current.node?.data?.uid;
    const textRaw = current.node?.data?.text;
    const children = Array.isArray(current.node?.children) ? current.node.children : [];
    nodes.push({
      uid:
        typeof uidRaw === "string" && uidRaw.trim()
          ? uidRaw
          : `depth:${current.depth}:index:${nodes.length}`,
      text: typeof textRaw === "string" && textRaw.trim() ? textRaw.trim() : "未命名节点",
      depth: current.depth,
      childCount: children.length,
    });
    children.forEach((child) => {
      queue.push({
        node: canonicalizeMindmapData(child),
        depth: current.depth + 1,
      });
    });
  }

  return nodes;
};

export const buildMindmapProjection = (input: {
  documentId: string;
  mindmapId: string;
  data: unknown;
  meta?: unknown;
}): MindmapProjection => {
  const data = canonicalizeMindmapData(input.data);
  const nodes = summarizeMindmapProjectionNodes(data);
  const meta = isRecord(input.meta) ? (input.meta as MindmapRouteMeta) : null;
  const rootNodeId = nodes[0]?.uid ?? null;

  return {
    projectionId: `mindmap_projection:${input.documentId}:${input.mindmapId}`,
    projection: "mindmap_subtree",
    documentId: input.documentId,
    mindmapId: input.mindmapId,
    rootNodeId,
    title: extractMindmapTitle(data),
    nodeCount: nodes.length,
    nodes,
    data,
    meta,
  };
};
