import type { SidebarInitialData } from "@/components/sidebar/types";
import {
  mapSidebarDatasetListQueryResultToInitialData,
  type SidebarDatasetListQueryResult,
} from "@/lib/sidebar-data";

export type TreeStreamKind = "snapshot" | "delta" | "resync";

export interface TreeStreamEnvelope {
  stream: string;
  workspaceId: string | null;
  rootNodeId: string | null;
  cursor: string | null;
  kind: TreeStreamKind;
  projection: string | null;
  data: unknown;
}

const TREE_STREAM_KINDS = new Set<TreeStreamKind>(["snapshot", "delta", "resync"]);

function isRecord(value: unknown): value is Record<string, unknown> {
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
}

function readString(value: unknown): string | null {
  return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
}

function readKind(value: unknown): TreeStreamKind | null {
  if (typeof value !== "string") {
    return null;
  }
  const normalized = value.trim().toLowerCase();
  return TREE_STREAM_KINDS.has(normalized as TreeStreamKind)
    ? (normalized as TreeStreamKind)
    : null;
}

function readNestedPayload(record: Record<string, unknown>): unknown {
  for (const key of ["data", "payload", "snapshot", "dataset", "sidebar"]) {
    if (key in record) {
      return record[key];
    }
  }
  return record;
}

function looksLikeSidebarInitialData(value: unknown): value is SidebarInitialData {
  return (
    isRecord(value) &&
    typeof value.activeWorkspaceId === "string" &&
    Array.isArray(value.documents)
  );
}

function looksLikeSidebarDatasetListQueryResult(
  value: unknown,
): value is SidebarDatasetListQueryResult {
  return (
    isRecord(value) &&
    typeof value.active_workspace_id === "string" &&
    Array.isArray(value.documents)
  );
}

export function buildWorkspaceTreeStreamUrl(
  workspaceId: string,
  cursor?: string | null,
): string {
  const baseOrigin =
    typeof window !== "undefined" ? window.location.origin : "http://127.0.0.1:3000";
  const url = new URL("/api/mnote-web/stream", baseOrigin);
  url.searchParams.set("workspaceId", workspaceId.trim());
  if (typeof cursor === "string" && cursor.trim()) {
    url.searchParams.set("cursor", cursor.trim());
  }
  return url.toString();
}

export function parseTreeStreamMessage(input: {
  rawData: string;
  eventType?: string | null;
}): TreeStreamEnvelope | null {
  let parsed: unknown;
  try {
    parsed = JSON.parse(input.rawData);
  } catch {
    return null;
  }

  if (!isRecord(parsed)) {
    return null;
  }

  const kind = readKind(parsed.kind) ?? readKind(input.eventType) ?? readKind(parsed.event);
  if (!kind) {
    return null;
  }

  return {
    stream: readString(parsed.stream) ?? "workspace",
    workspaceId: readString(parsed.workspaceId) ?? readString(parsed.workspace_id),
    rootNodeId: readString(parsed.rootNodeId) ?? readString(parsed.root_node_id),
    cursor: readString(parsed.cursor),
    kind,
    projection: readString(parsed.projection),
    data: readNestedPayload(parsed),
  };
}

export function normalizeTreeStreamSnapshot(data: unknown): SidebarInitialData | null {
  if (looksLikeSidebarInitialData(data)) {
    return data;
  }
  if (looksLikeSidebarDatasetListQueryResult(data)) {
    return mapSidebarDatasetListQueryResultToInitialData(data);
  }
  if (!isRecord(data)) {
    return null;
  }

  for (const key of ["snapshot", "dataset", "sidebar", "payload", "data"]) {
    if (!(key in data)) {
      continue;
    }
    const nested = normalizeTreeStreamSnapshot(data[key]);
    if (nested) {
      return nested;
    }
  }

  return null;
}
