import { randomUUID } from "node:crypto";
import { promises as fs } from "node:fs";
import path from "node:path";
import { NextResponse } from "next/server";
import { api } from "@/lib/convex/api";
import { getAuthedConvexClient } from "@/lib/convex/route";
import {
  buildDocumentBridgeContextWithActor,
  buildDocumentCommandEnvelope,
  documentBridgeErrorResponse,
  type BridgeContext,
  type CommandEnvelope,
} from "@/lib/documents/bridge";
import {
  recordBridgeCommandArtifacts,
  recordBridgeCommandFailureArtifacts,
} from "@/lib/documents/bridge-log";
import { executeRustBridgeMutationTransport, resolveRustBridgeCommandPlan } from "@/lib/documents/rust-runtime";
import { getDocumentsBaseDir } from "@/lib/server/local-paths";
import { filterTopLevelDocIds, isInvalidDocDrop } from "@/lib/file-tree/dnd";

type CreatePayload = {
  parentId?: string | null;
};

type MovePayload = {
  documentId?: string | null;
  parentId?: string | null;
  position?: number | null;
};

type DeletePayload = {
  documentId?: string | null;
};

type RestorePayload = {
  documentId?: string | null;
};

type DuplicatePayload = {
  documentId?: string | null;
};

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

type CopyTreePayload = {
  items?: CopyTreeItem[] | null;
  targetParentId?: string | null;
};

export type NormalizedDocumentMovePayload = {
  documentId: string | null;
  parentId: string | null;
  sortOrder: number;
};

export type NormalizedCopyTreeItem = {
  documentId: string;
  recursive: boolean;
};

export type NormalizedDocumentCopyTreePayload = {
  targetParentId: string | null;
  items: NormalizedCopyTreeItem[];
  sourceIds: string[];
};

const documentsBaseDir = getDocumentsBaseDir();

function assertServerEnvironment() {
  if (typeof process !== "undefined" && process.env.VITEST === "true") {
    return;
  }
  if (typeof window !== "undefined") {
    throw new Error("page-lifecycle-command-adapter 仅允许在服务端执行");
  }
}

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

function normalizeTitle(title: string | null): string {
  const safe = title?.trim();
  return safe && safe.length > 0 ? safe : "无标题";
}

export function normalizeDocumentMovePayload(payload: MovePayload): NormalizedDocumentMovePayload {
  return {
    documentId: trimOrNull(payload.documentId),
    parentId: trimOrNull(payload.parentId),
    sortOrder: Number.isFinite(payload.position ?? Number.NaN) ? Math.floor(payload.position ?? 0) : 0,
  };
}

export function normalizeDocumentCopyTreePayload(
  payload: CopyTreePayload,
): NormalizedDocumentCopyTreePayload {
  const items = (payload.items ?? [])
    .map((item) => ({
      documentId: trimOrNull(item?.documentId),
      recursive: Boolean(item?.recursive),
    }))
    .filter((item): item is NormalizedCopyTreeItem => Boolean(item.documentId))
    .map((item) => ({
      documentId: item.documentId,
      recursive: item.recursive,
    }));

  return {
    targetParentId: trimOrNull(payload.targetParentId),
    items,
    sourceIds: Array.from(new Set(items.map((item) => item.documentId))),
  };
}

export function resolveSubtreeMoveLegality(input: {
  sourceDocIds: string[];
  targetParentId: string | null;
  parentById: Map<string, string | null>;
}) {
  const topLevelSourceDocIds = filterTopLevelDocIds(input.sourceDocIds, input.parentById);
  return {
    sourceDocIds: topLevelSourceDocIds,
    targetParentId: input.targetParentId,
    isInvalid: isInvalidDocDrop({
      sourceDocIds: topLevelSourceDocIds,
      targetParentId: input.targetParentId,
      parentById: input.parentById,
    }),
  };
}

function safeRandomId() {
  return typeof crypto.randomUUID === "function"
    ? crypto.randomUUID()
    : randomUUID();
}

async function ensureDocumentScaffold(id: string, title: string | null) {
  const folder = path.join(documentsBaseDir, id);
  const indexFile = path.join(folder, "index.md");
  await fs.mkdir(folder, { recursive: true });
  try {
    await fs.access(indexFile);
  } catch {
    const safeTitle = normalizeTitle(title);
    await fs.writeFile(indexFile, `# ${safeTitle}\n`, "utf8");
  }
}

async function copyMindmapIfExists(sourceId: string, targetId: string) {
  try {
    const srcDir = path.join(documentsBaseDir, sourceId);
    const destDir = path.join(documentsBaseDir, targetId);
    const entries = await fs.readdir(srcDir);
    const mindmapFiles = entries.filter((name) => name === "mindmap.json" || /^mindmap-.+\.json$/i.test(name));
    if (mindmapFiles.length === 0) return;
    await fs.mkdir(destDir, { recursive: true });
    await Promise.all(
      mindmapFiles.map(async (name) => {
        try {
          const buf = await fs.readFile(path.join(srcDir, name));
          await fs.writeFile(path.join(destDir, name), buf);
        } catch {
          // ignore
        }
      }),
    );
  } catch {
    // 如果源文件不存在就跳过
  }
}

async function buildBridgeContext(request: Request, workspaceId: string | null, authUserId: string): Promise<BridgeContext> {
  const sessionId = trimOrNull(request.headers.get("x-session-id")) ?? trimOrNull(request.headers.get("x-mnote-session-id"));
  return buildDocumentBridgeContextWithActor({
    request,
    workspaceId,
    actor: {
      actorType: "user",
      actorId: authUserId,
      sessionId,
    },
  });
}

async function resolveCommandPlan<TPayload>(input: {
  request: Request;
  workspaceId: string | null;
  authUserId: string;
  envelope: CommandEnvelope<TPayload>;
}) {
  const context = await buildBridgeContext(input.request, input.workspaceId, input.authUserId);
  const plan = await resolveRustBridgeCommandPlan({
    context,
    envelope: input.envelope,
  });
  return { context, plan };
}

async function handleLifecycleError(error: unknown) {
  return documentBridgeErrorResponse(error);
}

export async function handleDocumentCreateRequest(request: Request): Promise<NextResponse> {
  assertServerEnvironment();
  try {
    const payload = (await request.json()) as CreatePayload;
    const { auth, client } = await getAuthedConvexClient();

    const parentId = trimOrNull(payload.parentId);
    const workspaceBootstrap = await client.mutation(api.workspaces.ensureDefaultWorkspace, {
      fallbackName: auth.email ?? auth.name ?? "我的空间",
      workspaceIdIfCreate: safeRandomId(),
    });

    let workspaceId: string | null = null;
    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 = parentDoc.workspace_id;
      accessScope = (parentDoc.access_scope ?? "private") as typeof accessScope;
    } else {
      workspaceId = workspaceBootstrap.activeWorkspaceId || null;
    }

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

    const documentId = safeRandomId();
    const context = await buildBridgeContext(request, workspaceId, auth.userId);
    const envelope = buildDocumentCommandEnvelope({
      name: "documents.create",
      payload: {
        documentId,
        workspaceId,
        parentId,
        title: "无标题",
        accessScope,
        content: [],
      },
      context,
      target: {
        workspaceId,
        pageId: documentId,
      },
    });
    const { context: runtimeContext, plan } = await resolveCommandPlan({
      request,
      workspaceId,
      authUserId: auth.userId,
      envelope,
    });

    const created = await executeRustBridgeMutationTransport<{
      id: string;
      title: string | null;
      parent_id: string | null;
      sort_order: number | null;
      is_starred: boolean;
      created_at: string;
      updated_at: string;
      workspace_id: string;
      access_scope: "private" | "shared" | "public";
      is_template: boolean;
    }>({
      client,
      plan,
    });

    if (created?.id) {
      await ensureDocumentScaffold(created.id, created.title ?? "无标题");
    }

    await recordBridgeCommandArtifacts({
      context: runtimeContext,
      envelope,
      client,
    });

    return NextResponse.json(created);
  } catch (error) {
    try {
      const payload = (await request.clone().json().catch(() => ({}))) as MovePayload;
      const documentId = trimOrNull(payload.documentId);
      if (documentId) {
        const { auth, client } = await getAuthedConvexClient();
        const sourceDoc = await client.query(api.documents.getMeta, { id: documentId });
        const context = await buildBridgeContext(request, sourceDoc?.workspace_id ?? null, auth.userId);
        const envelope = buildDocumentCommandEnvelope({
          name: "documents.move",
          payload: {
            documentId,
            parentId: trimOrNull(payload.parentId),
            sortOrder: Number.isFinite(payload.position ?? Number.NaN) ? Math.floor(payload.position ?? 0) : 0,
          },
          context,
          target: {
            workspaceId: sourceDoc?.workspace_id ?? null,
            pageId: documentId,
          },
        });
        await recordBridgeCommandFailureArtifacts({
          client,
          context,
          envelope,
          error,
        });
      }
    } catch {
      // 忽略日志写失败，保留原始错误返回
    }
    return handleLifecycleError(error);
  }
}

export async function handleDocumentMoveRequest(request: Request): Promise<NextResponse> {
  assertServerEnvironment();
  try {
    const payload = (await request.json()) as MovePayload;
    const normalizedMove = normalizeDocumentMovePayload(payload);
    const documentId = normalizedMove.documentId;
    if (!documentId) {
      return NextResponse.json({ error: "缺少 documentId" }, { status: 400 });
    }

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

    const context = await buildBridgeContext(request, sourceDoc.workspace_id ?? null, auth.userId);
    const envelope = buildDocumentCommandEnvelope({
      name: "documents.move",
      payload: {
        documentId,
        parentId: normalizedMove.parentId,
        sortOrder: normalizedMove.sortOrder,
      },
      context,
      target: {
        pageId: documentId,
      },
    });
    const { context: runtimeContext, plan } = await resolveCommandPlan({
      request,
      workspaceId: null,
      authUserId: auth.userId,
      envelope,
    });
    await executeRustBridgeMutationTransport({
      client,
      plan,
    });
    await recordBridgeCommandArtifacts({
      context: runtimeContext,
      envelope,
      client,
    });
    return NextResponse.json({ ok: true });
  } catch (error) {
    try {
      const payload = (await request.clone().json().catch(() => ({}))) as DeletePayload;
      const documentId = trimOrNull(payload.documentId);
      if (documentId) {
        const { auth, client } = await getAuthedConvexClient();
        const sourceDoc = await client.query(api.documents.getMeta, { id: documentId });
        const context = await buildBridgeContext(request, sourceDoc?.workspace_id ?? null, auth.userId);
        const envelope = buildDocumentCommandEnvelope({
          name: "documents.delete",
          payload: { documentId },
          context,
          target: {
            workspaceId: sourceDoc?.workspace_id ?? null,
            pageId: documentId,
          },
        });
        await recordBridgeCommandFailureArtifacts({
          client,
          context,
          envelope,
          error,
        });
      }
    } catch {
      // 忽略日志写失败，保留原始错误返回
    }
    return handleLifecycleError(error);
  }
}

export async function handleDocumentDeleteRequest(request: Request): Promise<NextResponse> {
  assertServerEnvironment();
  try {
    const payload = (await request.json()) as DeletePayload;
    const documentId = trimOrNull(payload.documentId);
    if (!documentId) {
      return NextResponse.json({ error: "缺少 documentId" }, { status: 400 });
    }

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

    const context = await buildBridgeContext(request, sourceDoc.workspace_id ?? null, auth.userId);
    const envelope = buildDocumentCommandEnvelope({
      name: "documents.delete",
      payload: { documentId },
      context,
      target: {
        pageId: documentId,
      },
    });
    const { context: runtimeContext, plan } = await resolveCommandPlan({
      request,
      workspaceId: null,
      authUserId: auth.userId,
      envelope,
    });
    await executeRustBridgeMutationTransport({
      client,
      plan,
    });
    await recordBridgeCommandArtifacts({
      context: runtimeContext,
      envelope,
      client,
    });
    return NextResponse.json({ success: true });
  } catch (error) {
    try {
      const payload = (await request.clone().json().catch(() => ({}))) as RestorePayload;
      const documentId = trimOrNull(payload.documentId);
      if (documentId) {
        const { auth, client } = await getAuthedConvexClient();
        const sourceDoc = await client.query(api.documents.getMeta, { id: documentId });
        const context = await buildBridgeContext(request, sourceDoc?.workspace_id ?? null, auth.userId);
        const envelope = buildDocumentCommandEnvelope({
          name: "documents.restore",
          payload: { documentId },
          context,
          target: {
            workspaceId: sourceDoc?.workspace_id ?? null,
            pageId: documentId,
          },
        });
        await recordBridgeCommandFailureArtifacts({
          client,
          context,
          envelope,
          error,
        });
      }
    } catch {
      // 忽略日志写失败，保留原始错误返回
    }
    return handleLifecycleError(error);
  }
}

export async function handleDocumentRestoreRequest(request: Request): Promise<NextResponse> {
  assertServerEnvironment();
  try {
    const payload = (await request.json()) as RestorePayload;
    const documentId = trimOrNull(payload.documentId);
    if (!documentId) {
      return NextResponse.json({ error: "缺少 documentId" }, { status: 400 });
    }

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

    const context = await buildBridgeContext(request, sourceDoc.workspace_id ?? null, auth.userId);
    const envelope = buildDocumentCommandEnvelope({
      name: "documents.restore",
      payload: { documentId },
      context,
      target: {
        pageId: documentId,
      },
    });
    const { context: runtimeContext, plan } = await resolveCommandPlan({
      request,
      workspaceId: null,
      authUserId: auth.userId,
      envelope,
    });
    await executeRustBridgeMutationTransport({
      client,
      plan,
    });
    await recordBridgeCommandArtifacts({
      context: runtimeContext,
      envelope,
      client,
    });
    return NextResponse.json({ success: true });
  } catch (error) {
    try {
      const payload = (await request.clone().json().catch(() => ({}))) as DuplicatePayload;
      const documentId = trimOrNull(payload.documentId);
      if (documentId) {
        const { auth, client } = await getAuthedConvexClient();
        const sourceDoc = await client.query(api.documents.getMeta, { id: documentId });
        const workspaceId = sourceDoc?.workspace_id ?? null;
        const context = await buildBridgeContext(request, workspaceId, auth.userId);
        const envelope = buildDocumentCommandEnvelope({
          name: "documents.duplicate",
          payload: {
            sourceDocumentId: documentId,
            newDocumentId: "duplicate_failed",
            title: sourceDoc?.title ?? null,
          },
          context,
          target: {
            workspaceId,
          },
        });
        await recordBridgeCommandFailureArtifacts({
          client,
          context,
          envelope,
          error,
        });
      }
    } catch {
      // 忽略日志写失败，保留原始错误返回
    }
    return handleLifecycleError(error);
  }
}

export async function handleDocumentDuplicateRequest(request: Request): Promise<NextResponse> {
  assertServerEnvironment();
  try {
    const payload = (await request.json()) as DuplicatePayload;
    const documentId = trimOrNull(payload.documentId);
    if (!documentId) {
      return NextResponse.json({ error: "缺少 documentId" }, { status: 400 });
    }

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

    const workspaceId = sourceDoc.workspace_id ?? null;
    const context = await buildBridgeContext(request, workspaceId, auth.userId);
    const fallbackTitle = normalizeTitle(sourceDoc.title);
    const duplicatedTitle = `${fallbackTitle} 副本`;
    const newId = safeRandomId();
    const envelope = buildDocumentCommandEnvelope({
      name: "documents.duplicate",
      payload: {
        sourceDocumentId: documentId,
        newDocumentId: newId,
        title: duplicatedTitle,
      },
      context,
      target: {
        workspaceId,
        pageId: newId,
      },
    });
    const { context: runtimeContext, plan } = await resolveCommandPlan({
      request,
      workspaceId,
      authUserId: auth.userId,
      envelope,
    });
    const duplicated = await executeRustBridgeMutationTransport<{
      id: string;
      title: string | null;
      parent_id: string | null;
      sort_order: number | null;
      workspace_id: string;
      access_scope: "private" | "shared" | "public";
      created_at: string;
      updated_at: string;
    }>({
      client,
      plan,
    });

    await ensureDocumentScaffold(duplicated.id, duplicated.title ?? duplicatedTitle);
    await copyMindmapIfExists(documentId, duplicated.id);

    await recordBridgeCommandArtifacts({
      context: runtimeContext,
      envelope,
      client,
    });

    return NextResponse.json({
      id: duplicated.id,
      title: duplicated.title ?? duplicatedTitle,
      parent_id: duplicated.parent_id ?? null,
      sort_order: duplicated.sort_order ?? null,
    });
  } catch (error) {
    try {
      const payload = (await request.clone().json().catch(() => ({}))) as CopyTreePayload;
      const { auth, client } = await getAuthedConvexClient();
      const context = await buildBridgeContext(request, null, auth.userId);
      const envelope = buildDocumentCommandEnvelope({
        name: "documents.copy_tree",
        payload: {
          items: (payload.items ?? []).map((item) => ({
            documentId: trimOrNull(item.documentId) ?? "unknown",
            recursive: Boolean(item.recursive),
          })),
          targetParentId: trimOrNull(payload.targetParentId),
        },
        context,
      });
      await recordBridgeCommandFailureArtifacts({
        client,
        context,
        envelope,
        error,
      });
    } catch {
      // 忽略日志写失败，保留原始错误返回
    }
    return handleLifecycleError(error);
  }
}

export async function handleDocumentCopyTreeRequest(request: Request): Promise<NextResponse> {
  assertServerEnvironment();
  try {
    const payload = (await request.json()) as CopyTreePayload;
    const { auth, client } = await getAuthedConvexClient();
    const normalizedCopyTree = normalizeDocumentCopyTreePayload(payload);
    if (normalizedCopyTree.items.length === 0) {
      return NextResponse.json({ error: "items 为空" }, { status: 400 });
    }
    const targetParentId = normalizedCopyTree.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 = targetDoc.workspace_id;
    }

    const sourceIds = normalizedCopyTree.sourceIds;
    const firstMeta = await client.query(api.documents.getMeta, { id: sourceIds[0] });
    if (!firstMeta) {
      return NextResponse.json({ error: "源页面不存在或无权限" }, { status: 404 });
    }

    if (!workspaceId) {
      workspaceId = firstMeta.workspace_id;
    }

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

    const context = await buildBridgeContext(request, workspaceId, auth.userId);
    const outerEnvelope = buildDocumentCommandEnvelope({
      name: "documents.copy_tree",
      payload: {
        items: normalizedCopyTree.items,
        targetParentId,
      },
      context,
      target: {
        workspaceId,
        pageId: targetParentId ?? undefined,
      },
    });
    const { context: runtimeContext, plan } = await resolveCommandPlan({
      request,
      workspaceId,
      authUserId: auth.userId,
      envelope: outerEnvelope,
    });
    const result = await executeRustBridgeMutationTransport<{
      items: Array<{ oldId: string; newId: string }>;
    }>({
      client,
      plan,
    });

    const insertedDocs = Array.isArray(result?.items) ? result.items : [];
    for (const item of insertedDocs) {
      const nextDoc = await client.query(api.documents.getMeta, { id: item.newId });
      await ensureDocumentScaffold(item.newId, nextDoc?.title ?? null);
      await copyMindmapIfExists(item.oldId, item.newId);
    }

    await recordBridgeCommandArtifacts({
      context: runtimeContext,
      envelope: outerEnvelope,
      client,
    });

    return NextResponse.json({
      items: insertedDocs,
    });
  } catch (error) {
    return handleLifecycleError(error);
  }
}
