import type { SidebarInitialData } from "@/components/sidebar/types";
import type { DocumentRecord } from "@/lib/documents";
import {
  buildKernelFileTreeProjection,
  type KernelFileTreeProjection,
} from "@/lib/kernel-file-tree";
import type { SidebarTreeNode } from "@/lib/kernel-sidebar";
import type { MediaAsset } from "@/types/media";

export function buildDocumentListSyncKey(documents: readonly DocumentRecord[]): string {
  return JSON.stringify(
    documents.map((document) => ({
      id: document.id,
      workspaceId: document.workspace_id,
      title: document.title ?? null,
      parentId: document.parent_id ?? null,
      sortOrder: document.sort_order ?? null,
      accessScope: document.access_scope,
      isStarred: document.is_starred ?? null,
      isTemplate: document.is_template,
      createdAt: document.created_at,
      updatedAt: document.updated_at ?? null,
    })),
  );
}

export function sidebarTreeNodeToDocumentRecord(
  node: SidebarTreeNode,
  fallbackWorkspaceId: string,
): DocumentRecord {
  return {
    access_scope: node.access_scope ?? "private",
    id: node.id,
    workspace_id: node.workspace_id || fallbackWorkspaceId,
    title: node.title ?? "无标题",
    parent_id: node.parent_id ?? null,
    sort_order: node.sort_order ?? null,
    is_starred: node.is_starred ?? false,
    is_template: node.is_template ?? false,
    created_at: node.created_at || "",
    updated_at: node.updated_at ?? node.created_at ?? null,
  };
}

export function upsertSidebarDocumentRecord(
  documents: readonly DocumentRecord[],
  document: DocumentRecord,
): DocumentRecord[] {
  let found = false;
  const next = documents.map((item) => {
    if (item.id !== document.id) {
      return item;
    }
    found = true;
    return document;
  });
  if (!found) {
    next.push(document);
  }
  return next;
}

export function renameSidebarDocumentRecord(
  documents: readonly DocumentRecord[],
  documentId: string,
  title: string,
  updatedAt: string | null,
): DocumentRecord[] {
  let changed = false;
  const next = documents.map((document) => {
    if (document.id !== documentId) {
      return document;
    }
    changed = true;
    return {
      ...document,
      title,
      updated_at: updatedAt ?? document.updated_at,
    };
  });
  return changed ? next : [...documents];
}

export function moveSidebarDocumentRecord(
  documents: readonly DocumentRecord[],
  documentId: string,
  parentId: string | null,
  sortOrder: number | null,
): DocumentRecord[] {
  let changed = false;
  const next = documents.map((document) => {
    if (document.id !== documentId) {
      return document;
    }
    changed = true;
    return {
      ...document,
      parent_id: parentId,
      sort_order: sortOrder,
    };
  });
  return changed ? next : [...documents];
}

export function removeSidebarDocumentRecords(
  documents: readonly DocumentRecord[],
  documentIds: readonly string[],
): DocumentRecord[] {
  const requestedIds = new Set(documentIds.map((id) => id.trim()).filter(Boolean));
  if (requestedIds.size === 0) {
    return [...documents];
  }

  const childrenByParentId = new Map<string, string[]>();
  documents.forEach((document) => {
    const parentId = document.parent_id?.trim();
    if (!parentId) {
      return;
    }
    const bucket = childrenByParentId.get(parentId) ?? [];
    bucket.push(document.id);
    childrenByParentId.set(parentId, bucket);
  });

  const idsToRemove = new Set<string>();
  const visit = (documentId: string) => {
    if (idsToRemove.has(documentId)) {
      return;
    }
    idsToRemove.add(documentId);
    (childrenByParentId.get(documentId) ?? []).forEach(visit);
  };
  requestedIds.forEach(visit);

  return documents.filter((document) => !idsToRemove.has(document.id));
}

export function buildSidebarLocalFileTreeProjection(input: {
  baseProjection: KernelFileTreeProjection;
  documents: readonly DocumentRecord[];
  mediaAssets?: readonly MediaAsset[] | null;
  mindmapAssets?: readonly MediaAsset[] | null;
  tableAssets?: readonly MediaAsset[] | null;
  mindmapAssetChildren?: SidebarInitialData["mindmapAssetChildren"];
}): KernelFileTreeProjection {
  return buildKernelFileTreeProjection({
    documents: [...input.documents],
    mediaAssets: [...(input.mediaAssets ?? [])],
    mindmapAssets: [...(input.mindmapAssets ?? [])],
    tableAssets: [...(input.tableAssets ?? [])],
    mindmapAssetChildren: input.mindmapAssetChildren ?? {},
    rootNodeId: input.baseProjection.rootNodeId,
  });
}
