import { randomUUID } from "node:crypto";
import { NextResponse } from "next/server";
import { api } from "@/lib/convex/api";
import { isConvexEnabled } from "@/lib/convex/enabled";
import { getAuthedConvexClient } from "@/lib/convex/route";
import {
  assertDocumentId,
  assertTitle,
  buildDocumentBridgeContext,
  buildDocumentCommandEnvelope,
  documentBridgeErrorResponse,
} from "@/lib/documents/bridge";
import {
  recordBridgeCommandFailureArtifacts,
} from "@/lib/documents/bridge-log";
import {
  copyMindmapFilesIfExists,
  ensureDocumentScaffold,
} from "@/lib/documents/page-lifecycle-side-effects";
import { loadSidebarDataFromConvex } from "@/lib/server/sidebar-data";
import {
  executeRustBridgeMutationTransport,
  recordRustBridgeCommandArtifacts,
  resolveRustBridgeCommandPlan,
} from "@/lib/documents/rust-runtime";

type TreeCommandAction =
  | "create"
  | "rename"
  | "move"
  | "archive"
  | "restore"
  | "purge"
  | "embed"
  | "copy";

type TreeCopyItem = {
  documentId: string;
  recursive: boolean;
};

type TreeCommandPayload = {
  action?: TreeCommandAction;
  workspaceId?: string | null;
  documentId?: string | null;
  parentId?: string | null;
  targetParentId?: string | null;
  title?: string | null;
  accessScope?: "private" | "shared" | "public" | null;
  content?: unknown;
  sortOrder?: number | null;
  sourceId?: string | null;
  targetId?: string | null;
  items?: TreeCopyItem[] | null;
};

type TreeDeltaDocument = {
  id: string;
  workspace_id: string;
  title: string | null;
  parent_id: string | null;
  sort_order: number | null;
  is_starred: boolean | null;
  access_scope: "private" | "shared" | "public";
  is_template: boolean;
  created_at: string;
  updated_at: string | null;
};

type TreeMutationResult<TResult> = {
  context: Awaited<ReturnType<typeof buildDocumentBridgeContext>>;
  envelope: ReturnType<typeof buildDocumentCommandEnvelope>;
  plan: Awaited<ReturnType<typeof resolveRustBridgeCommandPlan>>;
  result: TResult;
};

function trimOrNull(value: unknown) {
  if (typeof value !== "string") return null;
  const trimmed = value.trim();
  return trimmed.length > 0 ? trimmed : null;
}

function normalizeTitle(value: unknown) {
  const title = typeof value === "string" ? value.trim() : "";
  return title || "无标题";
}

function normalizeSortOrder(value: unknown) {
  return typeof value === "number" && Number.isFinite(value) ? Math.max(0, Math.floor(value)) : 0;
}

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

async function recordTreeCommandSuccess(args: {
  context: Awaited<ReturnType<typeof buildDocumentBridgeContext>>;
  envelope: ReturnType<typeof buildDocumentCommandEnvelope>;
  client: Awaited<ReturnType<typeof getAuthedConvexClient>>["client"];
  plan: Awaited<ReturnType<typeof resolveRustBridgeCommandPlan>>;
  result: unknown;
}) {
  try {
    await recordRustBridgeCommandArtifacts({
      context: args.context,
      envelope: args.envelope,
      client: args.client,
      plan: args.plan,
      result: args.result,
    });
  } catch (error) {
    console.warn("[tree.commands] Rust bridge success artifacts skipped:", error);
  }
}

async function loadTreeCommandSidebarSnapshot(args: {
  client: Awaited<ReturnType<typeof getAuthedConvexClient>>["client"];
  auth: Awaited<ReturnType<typeof getAuthedConvexClient>>["auth"];
  workspaceId: string | null;
}) {
  if (!args.workspaceId) {
    return null;
  }
  try {
    const result = await loadSidebarDataFromConvex({
      client: args.client,
      auth: {
        userId: args.auth.userId,
        email: args.auth.email,
        name: args.auth.name,
      },
      fallbackName: args.auth.email ?? args.auth.name ?? "我的空间",
      requestedWorkspaceId: args.workspaceId,
    });
    return result.sidebarInitialData ?? null;
  } catch (error) {
    console.warn("[tree.commands] sidebar snapshot skipped:", error);
    return null;
  }
}

function buildTreeMovePreflightDataFromSidebarSnapshot(
  sidebarSnapshot: unknown,
): Record<string, unknown> | null {
  if (!isRecord(sidebarSnapshot) || !Array.isArray(sidebarSnapshot.documents)) {
    return null;
  }
  return {
    documents: sidebarSnapshot.documents,
  };
}

async function resolveTreeMutationResult<TResult>(args: {
  request: Request;
  workspaceId: string | null;
  commandName: string;
  payload: unknown;
  preflightData?: Record<string, unknown> | null;
  pageId?: string | null;
  client: Awaited<ReturnType<typeof getAuthedConvexClient>>["client"];
}) {
  const context = await buildDocumentBridgeContext({
    request: args.request,
    workspaceId: args.workspaceId,
  });
  const envelope = buildDocumentCommandEnvelope({
    name: args.commandName,
    payload: args.payload,
    context,
    preflightData: args.preflightData ?? null,
    target: {
      workspaceId: args.workspaceId,
      pageId: args.pageId ?? undefined,
    },
    reason: `tree-route ${args.commandName}`,
    refs: ["next-tree-route"],
  });
  const plan = await resolveRustBridgeCommandPlan({
    context,
    envelope,
  });
  try {
    const result = await executeRustBridgeMutationTransport<TResult>({
      client: args.client,
      plan,
    });

    return {
      context,
      envelope,
      plan,
      result,
    };
  } catch (error) {
    await recordBridgeCommandFailureArtifacts({
      context,
      envelope,
      client: args.client,
      error,
    });
    throw error;
  }
}

export async function POST(request: Request) {
  if (!isConvexEnabled()) {
    return NextResponse.json({ error: "当前仅支持 Convex 模式" }, { status: 501 });
  }

  try {
    const payload = (await request.json()) as TreeCommandPayload;
    switch (payload.action) {
      case "create":
        return await handleCreate(request, payload);
      case "move":
        return await handleMove(request, payload);
      case "rename":
        return await handleRename(request, payload);
      case "archive":
        return await handleArchive(request, payload);
      case "restore":
        return await handleRestore(request, payload);
      case "purge":
        return await handlePurge(request, payload);
      case "embed":
        return await handleEmbed(request, payload);
      case "copy":
        return await handleCopy(request, payload);
      default:
        return NextResponse.json({ error: "不支持的 tree action" }, { status: 400 });
    }
  } catch (error) {
    return documentBridgeErrorResponse(error);
  }
}

async function handleCreate(request: Request, payload: TreeCommandPayload) {
  const { auth, client } = await getAuthedConvexClient();
  const parentId = trimOrNull(payload.parentId);
  const workspaceBootstrap = await client.mutation(api.workspaces.ensureDefaultWorkspace, {
    fallbackName: auth.email ?? auth.name ?? "我的空间",
    workspaceIdIfCreate: randomUUID(),
  });

  let workspaceId: string | null = trimOrNull(payload.workspaceId);
  let accessScope: "private" | "shared" | "public" = "private";
  if (parentId) {
    const parentDoc = await client.query(api.documents.getMeta, { id: parentId });
    if (!parentDoc) {
      return NextResponse.json({ error: "父页面不存在或无权限" }, { status: 404 });
    }
    workspaceId = trimOrNull(parentDoc.workspace_id);
    accessScope = (parentDoc.access_scope ?? "private") as typeof accessScope;
  } else if (!workspaceId) {
    workspaceId = trimOrNull(workspaceBootstrap.activeWorkspaceId);
  }

  if (!workspaceId) {
    return NextResponse.json({ error: "缺少目标工作空间" }, { status: 400 });
  }

  const documentId = trimOrNull(payload.documentId) ?? randomUUID();
  const title = normalizeTitle(payload.title);
  const mutation = await resolveTreeMutationResult<{
    id: string;
    document?: TreeDeltaDocument | null;
    title: string | null;
    parent_id: string | null;
    sort_order: number | null;
    workspace_id: string;
    access_scope: "private" | "shared" | "public";
    is_template: boolean;
    created_at: string;
    updated_at: string;
  }>({
    request,
    workspaceId,
    commandName: "tree.node.create",
    payload: {
      documentId,
      workspaceId,
      parentId,
      title,
      accessScope: trimOrNull(payload.accessScope) ?? accessScope,
      content: Array.isArray(payload.content) ? payload.content : [],
    },
    pageId: documentId,
    client,
  });
  const { context, envelope, result } = mutation;

  await ensureDocumentScaffold(result.id, result.title ?? title);
  await recordTreeCommandSuccess({
    context,
    envelope,
    client,
    plan: mutation.plan,
    result,
  });

  return NextResponse.json({
    requestId: context.requestId,
    traceId: context.traceId,
    result: {
      action: "create",
      workspaceId,
      documentId: result.id,
      parentId: result.parent_id ?? parentId,
      title: result.title ?? title,
      sortOrder: result.sort_order ?? null,
      updatedAt: result.updated_at ?? null,
      execution: result,
    },
  });
}

async function handleMove(request: Request, payload: TreeCommandPayload) {
  const { auth, client } = await getAuthedConvexClient();
  const documentId = assertDocumentId(payload.documentId ?? null);
  const sourceDoc = await client.query(api.documents.getMeta, { id: documentId });
  if (!sourceDoc) {
    return NextResponse.json({ error: "页面不存在或无权访问" }, { status: 404 });
  }

  const workspaceId = trimOrNull(payload.workspaceId) ?? trimOrNull(sourceDoc.workspace_id);
  const parentId = trimOrNull(payload.parentId);
  const sortOrder = normalizeSortOrder(payload.sortOrder);
  const sidebarSnapshot = await loadTreeCommandSidebarSnapshot({
    client,
    auth,
    workspaceId,
  });
  const movePreflightData = buildTreeMovePreflightDataFromSidebarSnapshot(sidebarSnapshot);
  const mutation = await resolveTreeMutationResult<{
    ok?: boolean;
    parent_id?: string | null;
    sort_order?: number | null;
    workspace_id?: string | null;
    updated_at?: string | null;
  }>({
    request,
    workspaceId,
    commandName: "tree.subtree.move",
    payload: {
      documentId,
      parentId,
      sortOrder,
    },
    preflightData: movePreflightData,
    pageId: documentId,
    client,
  });
  const { context, envelope, result } = mutation;
  await recordTreeCommandSuccess({
    context,
    envelope,
    client,
    plan: mutation.plan,
    result,
  });

  return NextResponse.json({
    requestId: context.requestId,
    traceId: context.traceId,
    result: {
      action: "move",
      workspaceId: trimOrNull(result?.workspace_id) ?? workspaceId,
      documentId,
      parentId: trimOrNull(result?.parent_id) ?? parentId,
      sortOrder:
        typeof result?.sort_order === "number" && Number.isFinite(result.sort_order)
          ? result.sort_order
          : sortOrder,
      updatedAt: trimOrNull(result?.updated_at) ?? null,
      execution: {
        ...(result ?? null),
        parent_id: trimOrNull(result?.parent_id) ?? parentId,
        sort_order:
          typeof result?.sort_order === "number" && Number.isFinite(result.sort_order)
            ? result.sort_order
            : sortOrder,
        workspace_id: trimOrNull(result?.workspace_id) ?? workspaceId,
      },
    },
  });
}

async function handleRename(request: Request, payload: TreeCommandPayload) {
  const { client } = await getAuthedConvexClient();
  const documentId = assertDocumentId(payload.documentId ?? null);
  const sourceDoc = await client.query(api.documents.getMeta, { id: documentId });
  if (!sourceDoc) {
    return NextResponse.json({ error: "页面不存在或无权访问" }, { status: 404 });
  }

  const workspaceId = trimOrNull(payload.workspaceId) ?? trimOrNull(sourceDoc.workspace_id);
  const title = assertTitle(payload.title ?? null);
  const mutation = await resolveTreeMutationResult<{
    ok?: boolean;
    document?: TreeDeltaDocument | null;
    updated_at?: string | null;
  }>({
    request,
    workspaceId,
    commandName: "tree.node.rename",
    payload: {
      documentId,
      workspaceId,
      title,
    },
    pageId: documentId,
    client,
  });
  const { context, envelope, result } = mutation;
  await recordTreeCommandSuccess({
    context,
    envelope,
    client,
    plan: mutation.plan,
    result,
  });

  return NextResponse.json({
    requestId: context.requestId,
    traceId: context.traceId,
    result: {
      action: "rename",
      workspaceId,
      documentId,
      title,
      updatedAt: result?.updated_at ?? null,
      execution: result ?? null,
    },
  });
}

async function handleArchive(request: Request, payload: TreeCommandPayload) {
  const { client } = await getAuthedConvexClient();
  const documentId = assertDocumentId(payload.documentId ?? null);
  const sourceDoc = await client.query(api.documents.getMeta, { id: documentId });
  if (!sourceDoc) {
    return NextResponse.json({ error: "页面不存在或无权访问" }, { status: 404 });
  }

  const workspaceId = trimOrNull(payload.workspaceId) ?? trimOrNull(sourceDoc.workspace_id);
  const mutation = await resolveTreeMutationResult<{
    ok?: boolean;
    document?: TreeDeltaDocument | null;
    updated_at?: string | null;
  }>({
    request,
    workspaceId,
    commandName: "tree.node.archive",
    payload: {
      documentId,
      workspaceId,
    },
    pageId: documentId,
    client,
  });
  const { context, envelope, result } = mutation;
  await recordTreeCommandSuccess({
    context,
    envelope,
    client,
    plan: mutation.plan,
    result,
  });

  return NextResponse.json({
    requestId: context.requestId,
    traceId: context.traceId,
    result: {
      action: "archive",
      workspaceId,
      documentId,
      updatedAt: result?.updated_at ?? null,
      execution: result ?? null,
    },
  });
}

async function handleRestore(request: Request, payload: TreeCommandPayload) {
  const { client } = await getAuthedConvexClient();
  const documentId = assertDocumentId(payload.documentId ?? null);
  const sourceDoc = await client.query(api.documents.getMeta, { id: documentId });
  if (!sourceDoc) {
    return NextResponse.json({ error: "页面不存在或无权访问" }, { status: 404 });
  }

  const workspaceId = trimOrNull(payload.workspaceId) ?? trimOrNull(sourceDoc.workspace_id);
  const mutation = await resolveTreeMutationResult<{
    ok?: boolean;
    document?: TreeDeltaDocument | null;
    updated_at?: string | null;
  }>({
    request,
    workspaceId,
    commandName: "tree.node.restore",
    payload: {
      documentId,
      workspaceId,
    },
    pageId: documentId,
    client,
  });
  const { context, envelope, result } = mutation;
  await recordTreeCommandSuccess({
    context,
    envelope,
    client,
    plan: mutation.plan,
    result,
  });

  return NextResponse.json({
    requestId: context.requestId,
    traceId: context.traceId,
    result: {
      action: "restore",
      workspaceId,
      documentId,
      updatedAt: result?.updated_at ?? null,
      execution: result ?? null,
    },
  });
}

async function handlePurge(request: Request, payload: TreeCommandPayload) {
  const { client } = await getAuthedConvexClient();
  const documentId = assertDocumentId(payload.documentId ?? null);
  const sourceDoc = await client.query(api.documents.getMeta, { id: documentId });
  if (!sourceDoc) {
    return NextResponse.json({ error: "页面不存在或无权访问" }, { status: 404 });
  }

  const workspaceId = trimOrNull(payload.workspaceId) ?? trimOrNull(sourceDoc.workspace_id);
  const mutation = await resolveTreeMutationResult<{
    ok?: boolean;
    purged?: boolean;
    purged_at?: string | null;
  }>({
    request,
    workspaceId,
    commandName: "tree.node.purge",
    payload: {
      documentId,
    },
    pageId: documentId,
    client,
  });
  const { context, envelope, result } = mutation;
  await recordTreeCommandSuccess({
    context,
    envelope,
    client,
    plan: mutation.plan,
    result,
  });

  return NextResponse.json({
    requestId: context.requestId,
    traceId: context.traceId,
    result: {
      action: "purge",
      workspaceId,
      documentId,
      purged: result?.purged ?? true,
      updatedAt: result?.purged_at ?? null,
      execution: result ?? null,
    },
  });
}

async function handleEmbed(request: Request, payload: TreeCommandPayload) {
  const { client } = await getAuthedConvexClient();
  const sourceId = assertDocumentId(payload.sourceId ?? null);
  const targetId = assertDocumentId(payload.targetId ?? null);

  const sourceDoc = await client.query(api.documents.getMeta, { id: sourceId });
  if (!sourceDoc) {
    return NextResponse.json({ error: "原始页面不存在或无权限" }, { status: 404 });
  }

  const targetContent = await client.query(api.documents.getContent, { id: targetId });
  if (!targetContent) {
    return NextResponse.json({ error: "目标页面不存在或无权限" }, { status: 404 });
  }
  const targetMeta = await client.query(api.documents.getMeta, { id: targetId });

  const anchorId = trimOrNull(
    (targetMeta as { embed_default_block_id?: string | null } | null)?.embed_default_block_id,
  );
  const workspaceId =
    trimOrNull(sourceDoc.workspace_id) ??
    trimOrNull((targetMeta as { workspace_id?: string | null } | null)?.workspace_id);

  const mutation = await resolveTreeMutationResult<{
    revision?: number | null;
    conflict_detection_key?: string | null;
  }>({
    request,
    workspaceId,
    commandName: "tree.node.embed",
    payload: {
      documentId: targetId,
      workspaceId,
      revision:
        typeof targetContent.revision === "number" && Number.isInteger(targetContent.revision)
          ? targetContent.revision
          : null,
      conflictDetectionKey:
        typeof targetContent.conflict_detection_key === "string"
          ? targetContent.conflict_detection_key
          : null,
      sourceDocumentId: sourceId,
      targetDocumentId: targetId,
      anchorBlockId: anchorId,
    },
    preflightData: {
      pageAggregateEmbed: {
        sourceDocumentId: sourceId,
        sourceTitle: sourceDoc.title ?? "无标题",
        targetDocumentId: targetId,
        targetContent: targetContent.content,
        anchorBlockId: anchorId,
        blockId: randomUUID(),
      },
    },
    pageId: targetId,
    client,
  });
  const { context, envelope, result } = mutation;
  await recordTreeCommandSuccess({
    context,
    envelope,
    client,
    plan: mutation.plan,
    result,
  });

  return NextResponse.json({
    requestId: context.requestId,
    traceId: context.traceId,
    result: {
      action: "embed",
      workspaceId,
      documentId: targetId,
      sourceDocumentId: sourceId,
      targetDocumentId: targetId,
      execution: result ?? null,
    },
  });
}

async function handleCopy(request: Request, payload: TreeCommandPayload) {
  const { client } = await getAuthedConvexClient();
  const normalizedItems = (payload.items ?? [])
    .filter((item) => item?.documentId)
    .map((item) => ({
      documentId: assertDocumentId(item.documentId),
      recursive: Boolean(item.recursive),
    }));

  if (normalizedItems.length === 0) {
    return NextResponse.json({ error: "items 为空" }, { status: 400 });
  }

  const targetParentId = trimOrNull(payload.targetParentId);
  let workspaceId: string | null = null;

  if (targetParentId) {
    const targetDoc = await client.query(api.documents.getMeta, { id: targetParentId });
    if (!targetDoc) {
      return NextResponse.json({ error: "目标页面不存在或无权限" }, { status: 404 });
    }
    workspaceId = trimOrNull(targetDoc.workspace_id);
  } else {
    const firstDoc = await client.query(api.documents.getMeta, {
      id: normalizedItems[0]?.documentId ?? "",
    });
    if (!firstDoc) {
      return NextResponse.json({ error: "源页面不存在或无权限" }, { status: 404 });
    }
    workspaceId = trimOrNull(firstDoc.workspace_id);
  }

  if (!workspaceId) {
    return NextResponse.json({ error: "缺少目标工作空间" }, { status: 400 });
  }

  const mutation = await resolveTreeMutationResult<{
    items: Array<{
      oldId: string;
      newId: string;
      title?: string | null;
      document?: TreeDeltaDocument | null;
    }>;
  }>({
    request,
    workspaceId,
    commandName: "tree.subtree.copy",
    payload: {
      workspaceId,
      targetParentId,
      items: normalizedItems,
    },
    pageId: targetParentId,
    client,
  });
  const { context, envelope, result } = mutation;

  await Promise.all(
    (result.items ?? []).map(async (item) => {
      await ensureDocumentScaffold(item.newId, item.title ?? "无标题");
      await copyMindmapFilesIfExists(item.oldId, item.newId);
    }),
  );
  await recordTreeCommandSuccess({
    context,
    envelope,
    client,
    plan: mutation.plan,
    result,
  });

  return NextResponse.json({
    requestId: context.requestId,
    traceId: context.traceId,
    result: {
      action: "copy",
      workspaceId,
      targetParentId,
      items: (result.items ?? []).map((item) => ({
        oldId: item.oldId,
        newId: item.newId,
      })),
      execution: result ?? null,
    },
  });
}

export const runtime = "nodejs";
