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

type SidebarTreeSnapshot = {
  id: string;
  title: string | null;
  parentId: string | null;
  sortOrder: number | null;
  updatedAt: string | null;
  children: SidebarTreeSnapshot[];
};

function toSidebarTreeSnapshot(nodes: SidebarTreeNode[]): SidebarTreeSnapshot[] {
  return nodes.map((node) => ({
    id: node.id,
    title: node.title ?? null,
    parentId: node.parent_id ?? null,
    sortOrder: node.sort_order ?? null,
    updatedAt: node.updated_at ?? null,
    children: toSidebarTreeSnapshot(node.children ?? []),
  }));
}

function toMediaAssetSnapshot(assets: MediaAsset[]) {
  return assets.map((asset) => ({
    id: asset.id,
    assetType: asset.asset_type,
    documentId: asset.document_id,
    fileName: asset.file_name ?? null,
    updatedAt: asset.updated_at ?? null,
    storagePath: asset.storage_path ?? null,
    fileUrl: asset.file_url ?? null,
  }));
}

function toMillis(value: string | null | undefined): number {
  if (!value) {
    return 0;
  }
  const parsed = Date.parse(value);
  return Number.isFinite(parsed) ? parsed : 0;
}

function normalizeKernelFileTreeProjection(
  projection: SidebarInitialData["kernelFileTreeProjection"] | undefined,
): KernelFileTreeProjection {
  return (
    projection ?? {
      projectionId: "kernel_projection:file_tree:missing",
      projection: "file_tree",
      rootNodeId: null,
      items: [],
      edges: [],
    }
  );
}

export function buildSidebarTreeSyncKey(nodes: SidebarTreeNode[]): string {
  return JSON.stringify(toSidebarTreeSnapshot(nodes));
}

export function buildMediaAssetListSyncKey(assets: MediaAsset[]): string {
  return JSON.stringify(toMediaAssetSnapshot(assets));
}

export function buildSidebarDataSyncKey(data: SidebarInitialData): string {
  const fileTreeProjection = normalizeKernelFileTreeProjection(data.kernelFileTreeProjection);
  return JSON.stringify({
    activeWorkspaceId: data.activeWorkspaceId,
    tree: toSidebarTreeSnapshot(data.kernelSidebarTree),
    fileTree: {
      projectionId: fileTreeProjection.projectionId,
      rootNodeId: fileTreeProjection.rootNodeId,
      items: fileTreeProjection.items.map((item) => ({
        rowId: item.rowId,
        rowKind: item.rowKind,
        nodeId: item.nodeId,
        parentNodeId: item.parentNodeId,
        title: item.title,
        depth: item.depth,
        position: item.position,
        childCount: item.childCount,
        expandable: item.expandable,
        expandedByDefault: item.expandedByDefault,
        iconHint: item.iconHint ?? null,
        resourceKind: item.resourceMeta.resourceKind,
        documentId: item.resourceMeta.documentId ?? null,
        assetId: item.resourceMeta.assetId ?? null,
        assetKind: item.resourceMeta.assetKind ?? null,
      })),
    },
    mediaAssets: toMediaAssetSnapshot(data.mediaAssets ?? []),
    mindmapAssets: toMediaAssetSnapshot(data.mindmapAssets ?? []),
    tableAssets: toMediaAssetSnapshot(data.tableAssets ?? []),
    trashedDocuments: (data.trashedDocuments ?? []).map((item) => ({
      id: item.id,
      title: item.title ?? null,
      parentId: item.parent_id ?? null,
      deletedAt: item.deleted_at,
      accessScope: item.access_scope,
    })),
    trashedMediaAssets: toMediaAssetSnapshot(data.trashedMediaAssets ?? []),
    trashedMindmapAssets: toMediaAssetSnapshot(data.trashedMindmapAssets ?? []),
    trashedTableAssets: toMediaAssetSnapshot(data.trashedTableAssets ?? []),
  });
}

export function getSidebarDataFreshness(data: SidebarInitialData): number {
  const documentTimes = data.documents.map((item) => toMillis(item.updated_at ?? item.created_at));
  const treeTimes = data.kernelSidebarTree.map((item) => toMillis(item.updated_at ?? item.created_at));
  const fileTreeProjection = normalizeKernelFileTreeProjection(data.kernelFileTreeProjection);
  const fileTreeTimes = fileTreeProjection.items.map((item) => item.position ?? 0);
  const assetTimes = [
    ...(data.mediaAssets ?? []),
    ...(data.mindmapAssets ?? []),
    ...(data.tableAssets ?? []),
    ...(data.trashedMediaAssets ?? []),
    ...(data.trashedMindmapAssets ?? []),
    ...(data.trashedTableAssets ?? []),
  ].map((item) => toMillis(item.updated_at ?? item.created_at));
  const trashedDocumentTimes = (data.trashedDocuments ?? []).map((item) => toMillis(item.deleted_at));

  return Math.max(
    0,
    ...documentTimes,
    ...treeTimes,
    ...fileTreeTimes,
    ...assetTimes,
    ...trashedDocumentTimes,
  );
}
