// 说明：这里保留的是 legacy/blob compat projection 工具，服务导图导入、
// 旧 React mindmap 参考实现和独立页兼容。Phase 6 文档页默认编辑主链
// 使用 Rust kernel projection 与 simple-mind-map adapter projection。
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 = {
  schema: "mnote.mindmap_projection.v1";
  projectionId: string;
  projection: "mindmap_subtree";
  source: string;
  owner: string;
  documentId: string;
  mindmapId: string;
  rootNodeId: string | null;
  title: string;
  nodeCount: number;
  nodes: MindmapProjectionNode[];
  data: MindMapData;
  meta: MindmapRouteMeta | null;
};

export type MindmapEditorSceneNode = MindmapProjectionNode & {
  id: string;
  parentId: string | null;
};

export type MindmapEditorSceneEdge = {
  id: string;
  source: string;
  target: string;
};

export type MindmapEditorScene = {
  schema: "mnote.mindmap_editor_scene.v1";
  source: string;
  owner: string;
  documentId: string;
  mindmapId: string;
  rootNodeId: string | null;
  title: string;
  nodes: MindmapEditorSceneNode[];
  edges: MindmapEditorSceneEdge[];
  capabilities: {
    canEditText: boolean;
    canAddChild: boolean;
    canAddSiblingAfter: boolean;
    canDeleteNode: boolean;
  };
  data: MindMapData;
  meta: MindmapRouteMeta | null;
};

export type MindmapSimpleMindMapScene = {
  schema: "mnote.mindmap.simple_mind_map_scene.v1";
  runtime: "simple-mind-map";
  documentId: string;
  mindmapId: string;
  rootNodeId: string | null;
  root: MindMapData;
  layout: unknown;
  theme: unknown;
  themeConfig: unknown;
  view: unknown;
  config: unknown;
  compatPayload: unknown;
  kernelRevision: number;
  source: string;
  owner: string;
  meta: MindmapRouteMeta | null;
};

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

export const DEFAULT_MINDMAP_LAYOUT = "logicalStructure";
export const DEFAULT_MINDMAP_THEME = "default";

export const createDefaultMindmapThemeConfig = (): Record<string, unknown> => ({
  lineColor: "#7aa2ff",
  lineStyle: "curve",
  rootLineKeepSameInCurve: true,
  rootLineStartPositionKeepSameInCurve: true,
  generalizationLineColor: "#ef6a5b",
  backgroundColor: "#f6f8fc",
  root: {
    fillColor: "#e25563",
    color: "#ffffff",
    fontWeight: "bold",
    borderColor: "transparent",
    borderWidth: 0,
    borderRadius: 8,
  },
  second: {
    fillColor: "#4f7df3",
    color: "#ffffff",
    borderColor: "transparent",
    borderWidth: 0,
    borderRadius: 8,
  },
  node: {
    fillColor: "transparent",
    color: "#315aa9",
    borderColor: "transparent",
    borderWidth: 0,
  },
  generalization: {
    fillColor: "#ffffff",
    color: "#ef6a5b",
    borderColor: "#ef6a5b",
    borderWidth: 1,
    borderRadius: 8,
  },
});

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;
    const data = isRecord(node.data) ? node.data : {};
    node.data = data;
    const rawText = data.text;
    data.text = typeof rawText === "string" ? rawText : String(rawText ?? "");

    const gen = 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;
  source?: string;
  owner?: string;
  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 {
    schema: "mnote.mindmap_projection.v1",
    projectionId: `mindmap_projection:${input.documentId}:${input.mindmapId}`,
    projection: "mindmap_subtree",
    source: input.source ?? "rust-kernel",
    owner: input.owner ?? "rust-kernel",
    documentId: input.documentId,
    mindmapId: input.mindmapId,
    rootNodeId,
    title: extractMindmapTitle(data),
    nodeCount: nodes.length,
    nodes,
    data,
    meta,
  };
};

export const buildMindmapEditorScene = (input: {
  documentId: string;
  mindmapId: string;
  rootNodeId?: string | null;
  data: unknown;
  source?: string;
  owner?: string;
  meta?: unknown;
}): MindmapEditorScene => {
  const data = canonicalizeMindmapData(input.data);
  const meta = isRecord(input.meta) ? (input.meta as MindmapRouteMeta) : null;
  const nodes: MindmapEditorSceneNode[] = [];
  const edges: MindmapEditorSceneEdge[] = [];

  const walk = (node: MindMapData, depth: number, parentId: string | null) => {
    const uidRaw = node?.data?.uid;
    const textRaw = node?.data?.text;
    const id =
      typeof uidRaw === "string" && uidRaw.trim()
        ? uidRaw.trim()
        : `depth:${depth}:index:${nodes.length}`;
    const children = Array.isArray(node?.children) ? node.children : [];
    nodes.push({
      id,
      uid: id,
      text: typeof textRaw === "string" && textRaw.trim() ? textRaw.trim() : "未命名节点",
      depth,
      childCount: children.length,
      parentId,
    });
    if (parentId) {
      edges.push({
        id: `${parentId}->${id}`,
        source: parentId,
        target: id,
      });
    }
    children.forEach((child) => {
      walk(canonicalizeMindmapData(child), depth + 1, id);
    });
  };

  walk(data, 0, null);
  const fallbackRootId = nodes[0]?.id ?? null;
  const rootNodeId = input.rootNodeId && input.rootNodeId.trim() ? input.rootNodeId.trim() : fallbackRootId;

  return {
    schema: "mnote.mindmap_editor_scene.v1",
    source: input.source ?? "rust-kernel",
    owner: input.owner ?? "rust-kernel",
    documentId: input.documentId,
    mindmapId: input.mindmapId,
    rootNodeId,
    title: extractMindmapTitle(data),
    nodes,
    edges,
    capabilities: {
      canEditText: true,
      canAddChild: true,
      canAddSiblingAfter: true,
      canDeleteNode: true,
    },
    data,
    meta,
  };
};

export const buildMindmapSimpleMindMapScene = (input: {
  documentId: string;
  mindmapId: string;
  data: unknown;
  source?: string;
  owner?: string;
  meta?: unknown;
}): MindmapSimpleMindMapScene => {
  const root = canonicalizeMindmapData(input.data);
  const meta = isRecord(input.meta) ? (input.meta as MindmapRouteMeta) : null;
  const rootNodeIdRaw = root?.data?.uid;
  const rootNodeId = typeof rootNodeIdRaw === "string" && rootNodeIdRaw.trim() ? rootNodeIdRaw.trim() : "root";
  if (!root.data.uid) {
    root.data.uid = rootNodeId;
  }

  return {
    schema: "mnote.mindmap.simple_mind_map_scene.v1",
    runtime: "simple-mind-map",
    documentId: input.documentId,
    mindmapId: input.mindmapId,
    rootNodeId,
    root,
    layout: DEFAULT_MINDMAP_LAYOUT,
    theme: DEFAULT_MINDMAP_THEME,
    themeConfig: createDefaultMindmapThemeConfig(),
    view: { x: 0, y: 0, scale: 1 },
    config: {},
    compatPayload: {},
    kernelRevision: 1,
    source: input.source ?? "rust-kernel",
    owner: input.owner ?? "rust-kernel",
    meta,
  };
};
