import type { SidebarInitialData } from "@/components/sidebar/types";
import type { DocumentRecord } from "@/lib/documents";
import {
  buildKernelFileTreeProjection,
  isKernelFileTreeProjection,
  type KernelFileTreeProjection,
} from "@/lib/kernel-file-tree";
import {
  buildKernelSidebarProjection as buildProjectionContract,
  buildSidebarTreeFromKernelProjection,
  type KernelSidebarProjection,
} from "@/lib/kernel-sidebar";
import type { WorkspaceSummary } from "@/lib/workspaces";
import type { MediaAsset } from "@/types/media";

type MindmapRow = {
  mindmap_id: string;
  workspace_id?: string | null;
  document_id: string;
  data?: unknown;
  created_at?: string | null;
  updated_at?: string | null;
  deleted_at?: string | null;
  deleted_by?: string | null;
};

type TableRow = {
  id: string;
  workspace_id?: string | null;
  document_id: string;
  title?: string | null;
  created_at?: string | null;
  updated_at?: string | null;
  deleted_at?: string | null;
  deleted_by?: string | null;
  purged_at?: string | null;
  is_archived?: boolean | null;
};

export type SidebarDatasetInput = {
  activeWorkspaceId: string;
  workspaces: WorkspaceSummary[];
  documents: DocumentRecord[];
  trashedDocuments: SidebarInitialData["trashedDocuments"];
  mindmaps: MindmapRow[];
  mediaAssets?: MediaAsset[] | null;
  trashedMediaAssets?: MediaAsset[] | null;
  tables?: TableRow[] | null;
};

export type SidebarDatasetListQueryPayload = {
  workspace_id: string;
};

export type SidebarDatasetListQueryResult = {
  active_workspace_id: string;
  workspaces: WorkspaceSummary[];
  documents: DocumentRecord[];
  kernel_file_tree_projection?: KernelFileTreeProjection;
  kernelFileTreeProjection?: KernelFileTreeProjection;
  kernel_sidebar_projection?: KernelSidebarProjection;
  kernelSidebarProjection?: KernelSidebarProjection;
  trashed_documents: SidebarInitialData["trashedDocuments"];
  media_assets: MediaAsset[];
  trashed_media_assets: MediaAsset[];
  mindmap_assets: MediaAsset[];
  trashed_mindmap_assets: MediaAsset[];
  table_assets: MediaAsset[];
  trashed_table_assets: MediaAsset[];
  mindmap_docs: string[];
  mindmap_asset_children: Record<string, string[]>;
};

const EMPTY_KERNEL_SIDEBAR_PROJECTION: KernelSidebarProjection = {
  projectionId: "kernel_projection:sidebar_tree:missing",
  projection: "sidebar_tree",
  rootNodeId: null,
  items: [],
  edges: [],
};

const EMPTY_KERNEL_FILE_TREE_PROJECTION: KernelFileTreeProjection = {
  projectionId: "kernel_projection:file_tree:missing",
  projection: "file_tree",
  rootNodeId: null,
  items: [],
  edges: [],
};

function isKernelSidebarProjection(value: unknown): value is KernelSidebarProjection {
  return (
    Boolean(value) &&
    typeof value === "object" &&
    Array.isArray((value as KernelSidebarProjection).items) &&
    Array.isArray((value as KernelSidebarProjection).edges)
  );
}

function readKernelSidebarProjection(
  result: SidebarDatasetListQueryResult,
): KernelSidebarProjection {
  const snakeCaseProjection =
    "kernel_sidebar_projection" in result ? result.kernel_sidebar_projection : undefined;
  if (isKernelSidebarProjection(snakeCaseProjection)) {
    return snakeCaseProjection;
  }

  const camelCaseProjection =
    "kernelSidebarProjection" in result ? result.kernelSidebarProjection : undefined;
  if (isKernelSidebarProjection(camelCaseProjection)) {
    return camelCaseProjection;
  }

  if (Array.isArray(result.documents) && result.documents.length > 0) {
    // 说明：部分 query transport 只回 documents，没有同步附带 projection。
    // 这里按同一协议即时重建，避免 UI 把缺失节点全部降级到根层。
    return buildProjectionContract(result.documents);
  }

  return EMPTY_KERNEL_SIDEBAR_PROJECTION;
}

function readKernelFileTreeProjection(
  result: SidebarDatasetListQueryResult,
): KernelFileTreeProjection {
  const snakeCaseProjection =
    "kernel_file_tree_projection" in result ? result.kernel_file_tree_projection : undefined;
  if (isKernelFileTreeProjection(snakeCaseProjection)) {
    return snakeCaseProjection;
  }

  const camelCaseProjection =
    "kernelFileTreeProjection" in result ? result.kernelFileTreeProjection : undefined;
  if (isKernelFileTreeProjection(camelCaseProjection)) {
    return camelCaseProjection;
  }

  if (Array.isArray(result.documents)) {
    return buildKernelFileTreeProjection({
      documents: result.documents,
      mediaAssets: result.media_assets,
      mindmapAssets: result.mindmap_assets,
      tableAssets: result.table_assets,
      mindmapAssetChildren: result.mindmap_asset_children,
    });
  }

  return EMPTY_KERNEL_FILE_TREE_PROJECTION;
}

function normalizeStringArray(values: Iterable<string>): string[] {
  return Array.from(new Set(values)).filter((value) => value.trim().length > 0);
}

export function buildSidebarDatasetListQueryPayload(
  workspaceId: string,
): SidebarDatasetListQueryPayload {
  return {
    workspace_id: workspaceId.trim(),
  };
}

export function extractMindmapImageAssetIdsFromData(input: unknown): string[] {
  const root = (() => {
    if (!input || typeof input !== "object") return input;
    const record = input as Record<string, unknown>;
    return record && typeof record === "object" && "root" in record ? record.root : input;
  })();

  const ids: string[] = [];
  const seen = new Set<string>();

  const push = (value: unknown) => {
    if (typeof value !== "string") return;
    if (!value.startsWith("asset:")) return;
    const id = value.slice("asset:".length).trim();
    if (!id || seen.has(id)) return;
    seen.add(id);
    ids.push(id);
  };

  const get = (obj: unknown, key: string): unknown => {
    if (!obj || typeof obj !== "object") return undefined;
    return (obj as Record<string, unknown>)[key];
  };

  const walk = (node: unknown) => {
    if (!node || typeof node !== "object") return;

    const data = get(node, "data");
    const image = get(node, "image");

    push(get(data, "image"));
    push(image);
    push(get(image, "url"));
    push(get(get(data, "image"), "url"));

    const children = get(node, "children");
    if (Array.isArray(children)) {
      children.forEach(walk);
    }
  };

  walk(root);
  return ids;
}

function toMindmapAsset(row: MindmapRow, workspaceId: string): MediaAsset {
  const isLegacy = row.mindmap_id.startsWith("legacy-");
  return {
    id: row.mindmap_id,
    workspace_id: row.workspace_id ?? workspaceId,
    document_id: row.document_id,
    asset_type: "mindmap",
    file_url: null,
    thumbnail_url: null,
    bucket: null,
    storage_path: null,
    file_name: isLegacy ? "mindmap.json" : `mindmap-${row.mindmap_id}.json`,
    file_size: null,
    mime_type: "application/json",
    ocr_payload: undefined,
    ocr_strategy: null,
    ocr_text: null,
    ocr_status: null,
    signed_url: null,
    created_at: row.created_at ?? "",
    updated_at: row.updated_at ?? "",
  };
}

function toTrashedMindmapAsset(row: MindmapRow, workspaceId: string): MediaAsset {
  return {
    ...toMindmapAsset(row, workspaceId),
    deleted_at: row.deleted_at ?? null,
    deleted_by: row.deleted_by ?? null,
    purged_at: null,
  };
}

function toTableAsset(row: TableRow, workspaceId: string): MediaAsset {
  const base = String(row.title ?? "未命名表格").trim() || "未命名表格";
  const fileName = base.toLowerCase().endsWith(".luckysheet") ? base : `${base}.luckysheet`;
  return {
    id: row.id,
    workspace_id: row.workspace_id ?? workspaceId,
    document_id: row.document_id,
    asset_type: "luckysheet",
    file_url: null,
    thumbnail_url: null,
    bucket: null,
    storage_path: null,
    file_name: fileName,
    file_size: null,
    mime_type: "application/json",
    ocr_payload: undefined,
    ocr_strategy: null,
    ocr_text: null,
    ocr_status: null,
    signed_url: null,
    created_at: row.created_at ?? "",
    updated_at: row.updated_at ?? "",
  };
}

function toTrashedTableAsset(row: TableRow, workspaceId: string): MediaAsset {
  return {
    ...toTableAsset(row, workspaceId),
    deleted_at: row.deleted_at ?? row.updated_at ?? null,
    deleted_by: row.deleted_by ?? null,
    purged_at: row.purged_at ?? null,
  };
}

function deriveSidebarDataset(input: SidebarDatasetInput) {
  const activeMindmaps = input.mindmaps.filter((row) => !row.deleted_at);
  const trashedMindmaps = input.mindmaps.filter((row) => Boolean(row.deleted_at));
  const activeTables = (input.tables ?? []).filter((row) => !row.is_archived);
  const trashedTables = (input.tables ?? []).filter((row) => Boolean(row.is_archived));

  const mindmapAssetChildren: Record<string, string[]> = {};
  activeMindmaps.forEach((row) => {
    const ids = extractMindmapImageAssetIdsFromData(row.data);
    if (ids.length > 0) {
      mindmapAssetChildren[row.mindmap_id] = ids;
    }
  });

  return {
    mindmapAssetChildren,
    mindmapAssets: activeMindmaps.map((row) => toMindmapAsset(row, input.activeWorkspaceId)),
    mindmapDocs: normalizeStringArray(activeMindmaps.map((row) => row.document_id)),
    tableAssets: activeTables.map((row) => toTableAsset(row, input.activeWorkspaceId)),
    trashedMindmapAssets: trashedMindmaps.map((row) =>
      toTrashedMindmapAsset(row, input.activeWorkspaceId),
    ),
    trashedTableAssets: trashedTables.map((row) =>
      toTrashedTableAsset(row, input.activeWorkspaceId),
    ),
  };
}

export function buildSidebarDatasetListQueryResult(
  input: SidebarDatasetInput,
): SidebarDatasetListQueryResult {
  const derived = deriveSidebarDataset(input);
  const kernelSidebarProjection = buildProjectionContract(input.documents);
  const kernelFileTreeProjection = buildKernelFileTreeProjection({
    documents: input.documents,
    mediaAssets: input.mediaAssets,
    mindmapAssets: derived.mindmapAssets,
    tableAssets: derived.tableAssets,
    mindmapAssetChildren: derived.mindmapAssetChildren,
  });

  return {
    active_workspace_id: input.activeWorkspaceId,
    workspaces: [...input.workspaces],
    documents: [...input.documents],
    kernel_file_tree_projection: kernelFileTreeProjection,
    kernel_sidebar_projection: kernelSidebarProjection,
    trashed_documents: [...input.trashedDocuments],
    media_assets: [...(input.mediaAssets ?? [])],
    trashed_media_assets: [...(input.trashedMediaAssets ?? [])],
    mindmap_assets: derived.mindmapAssets,
    trashed_mindmap_assets: derived.trashedMindmapAssets,
    table_assets: derived.tableAssets,
    trashed_table_assets: derived.trashedTableAssets,
    mindmap_docs: derived.mindmapDocs,
    mindmap_asset_children: { ...derived.mindmapAssetChildren },
  };
}

export function mapSidebarDatasetListQueryResultToInitialData(
  result: SidebarDatasetListQueryResult,
): SidebarInitialData {
  const kernelSidebarProjection = readKernelSidebarProjection(result);
  const kernelFileTreeProjection = readKernelFileTreeProjection(result);

  return {
    activeWorkspaceId: result.active_workspace_id,
    workspaces: [...result.workspaces],
    documents: [...result.documents],
    kernelSidebarProjection,
    kernelSidebarTree: buildSidebarTreeFromKernelProjection({
      records: result.documents,
      projection: kernelSidebarProjection,
    }),
    kernelFileTreeProjection,
    trashedDocuments: [...result.trashed_documents],
    trashedMediaAssets: [...result.trashed_media_assets],
    trashedMindmapAssets: [...result.trashed_mindmap_assets],
    trashedTableAssets: [...result.trashed_table_assets],
    mindmapDocs: [...result.mindmap_docs],
    mindmapAssets: [...result.mindmap_assets],
    mindmapAssetChildren: { ...result.mindmap_asset_children },
    tableAssets: [...result.table_assets],
    mediaAssets: [...result.media_assets],
  };
}

export function buildSidebarInitialData(input: SidebarDatasetInput): SidebarInitialData {
  const queryResult = buildSidebarDatasetListQueryResult(input);

  return mapSidebarDatasetListQueryResultToInitialData(queryResult);
}
