import { v } from "convex/values";
import { query } from "./_generated/server";
import { api } from "./_generated/api";
import { requireUserId } from "./_utils/auth";

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;
};

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

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) {
  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) {
  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) {
  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) {
  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,
  };
}

export const datasetList = query({
  args: {
    workspaceId: v.string(),
  },
  handler: async (ctx, args) => {
    const userId = await requireUserId(ctx);

    // 说明：这条查询作为 Sidebar 的单一数据集入口，先复用现有稳定 query，
    // 把前端原先“多 query + 多处拼装”收口成一条主查询契约。
    const [
      workspacesResult,
      documents,
      trashedDocuments,
      mindmaps,
      mediaAssets,
      trashedMediaAssets,
      tables,
    ] = await Promise.all([
      ctx.runQuery(api.workspaces.fetchWorkspaceSummaries, {}),
      ctx.runQuery(api.documents.listByWorkspace, {
        workspaceId: args.workspaceId,
      }),
      ctx.runQuery(api.documents.listTrashedByWorkspace, {
        workspaceId: args.workspaceId,
      }),
      ctx.runQuery(api.mindmaps.listByWorkspace, {
        workspaceId: args.workspaceId,
        includeDeleted: true,
      }),
      ctx.runQuery(api.mediaAssets.listByWorkspace, {
        userId,
        workspaceId: args.workspaceId,
        limit: 200,
      }),
      ctx.runQuery(api.mediaAssets.listDeletedByWorkspace, {
        userId,
        workspaceId: args.workspaceId,
        limit: 2000,
      }),
      ctx.runQuery(api.tables.listByWorkspaceForSearch, {
        userId,
        workspaceId: args.workspaceId,
        includeArchived: true,
        limit: 3000,
      }),
    ]);

    const activeMindmaps = (mindmaps as MindmapRow[]).filter((row) => !row.deleted_at);
    const trashedMindmaps = (mindmaps as MindmapRow[]).filter((row) => Boolean(row.deleted_at));
    const activeTables = (tables as TableRow[]).filter((row) => !row.is_archived);
    const trashedTables = (tables as TableRow[]).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 {
      active_workspace_id: args.workspaceId,
      workspaces: workspacesResult.workspaces,
      documents,
      trashed_documents: trashedDocuments,
      media_assets: mediaAssets ?? [],
      trashed_media_assets: trashedMediaAssets ?? [],
      mindmap_assets: activeMindmaps.map((row) => toMindmapAsset(row, args.workspaceId)),
      trashed_mindmap_assets: trashedMindmaps.map((row) =>
        toTrashedMindmapAsset(row, args.workspaceId),
      ),
      table_assets: activeTables.map((row) => toTableAsset(row, args.workspaceId)),
      trashed_table_assets: trashedTables.map((row) => toTrashedTableAsset(row, args.workspaceId)),
      mindmap_docs: normalizeStringArray(activeMindmaps.map((row) => row.document_id)),
      mindmap_asset_children: mindmapAssetChildren,
    };
  },
});
