"use client";

import type {
  PageLayoutCommandInput,
  PageTitleCommandInput,
} from "@/lib/documents/page-command-contract";
import {
  executePageHeadCommand,
  executePageLayoutCommand,
  type PageHeadCommandResult,
  type PageLayoutCommandResult,
} from "@/lib/documents/page-command-client";
import type { PageOptionsState } from "@/types/page-options";

type DocumentCommandMeta = {
  requestId?: string;
  traceId?: string;
  commandId?: string;
  commandName?: string;
};

type DocumentCommandErrorPayload = {
  error?: string;
};

export const TREE_COMMAND_PROTOCOL = {
  create: {
    preferredCommandName: "tree.node.create",
    compatCommandName: "documents.create",
  },
  rename: {
    preferredCommandName: "tree.node.rename",
    compatCommandName: "documents.title.update",
  },
  move: {
    preferredCommandName: "tree.subtree.move",
    compatCommandName: "documents.move",
  },
  archive: {
    preferredCommandName: "tree.node.archive",
    compatCommandName: "documents.delete",
  },
  restore: {
    preferredCommandName: "tree.node.restore",
    compatCommandName: "documents.restore",
  },
  purge: {
    preferredCommandName: "tree.node.purge",
    compatCommandName: "documents.purge",
  },
  embed: {
    preferredCommandName: "tree.node.embed",
    compatCommandName: "documents.embed",
  },
  copy: {
    preferredCommandName: "tree.subtree.copy",
    compatCommandName: "documents.copy_tree",
  },
} as const;

export type DocumentCreateCommandResult = {
  id: string;
  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 | null;
  updated_at?: string | null;
  meta?: DocumentCommandMeta;
};

export type DocumentCreateChildCommandResult = {
  pageId: string;
  title?: string | null;
  meta?: DocumentCommandMeta;
};

type RenameDocumentInput = {
  documentId: string;
  workspaceId?: string | null;
  title: string;
};

type UpdatePageOptionsInput = {
  documentId: string;
  workspaceId?: string | null;
  pageOptions: Partial<PageOptionsState>;
};

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

type TreeCommandAction = "create" | "rename" | "move";

type DeleteDocumentInput = {
  documentId: string;
  workspaceId?: string | null;
};

type RestoreDocumentInput = {
  documentId: string;
  workspaceId?: string | null;
};

type PurgeDocumentInput = {
  documentId: string;
};

type EmbedDocumentInput = {
  sourceId: string;
  targetId: string;
};

type CopyTreeCommandInput = {
  targetParentId: string | null;
  items: Array<{
    documentId: string;
    recursive: boolean;
  }>;
};

type CreateChildDocumentInput = {
  parentId: string | null;
  title: string;
  blocks: unknown[];
};

async function postDocumentCommand<TResult>(path: string, payload: unknown, fallbackMessage: string): Promise<TResult> {
  const response = await fetch(path, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(payload),
  });

  const body = (await response.json().catch(() => null)) as TResult | DocumentCommandErrorPayload | null;
  if (!response.ok) {
    const message =
      body && typeof body === "object" && "error" in body && typeof body.error === "string"
        ? body.error
        : fallbackMessage;
    throw new Error(message);
  }

  return body as TResult;
}

type TreeCommandResponse = {
  requestId?: string;
  traceId?: string;
  result?: {
    action?: TreeCommandAction;
    workspaceId?: string | null;
    documentId?: string;
    parentId?: string | null;
    title?: string | null;
    sortOrder?: number | null;
    updatedAt?: string | null;
    execution?: {
      access_scope?: "private" | "shared" | "public";
      is_template?: boolean;
      created_at?: string | null;
      updated_at?: string | null;
    } | null;
  } | null;
};

async function postTreeCommand<TResult>(payload: unknown, fallbackMessage: string): Promise<TResult> {
  return postDocumentCommand<TResult>("/api/tree/commands", payload, fallbackMessage);
}

export async function createDocumentCommand(parentId: string | null): Promise<DocumentCreateCommandResult> {
  const response = await postTreeCommand<TreeCommandResponse>(
    {
      action: "create",
      parentId,
    },
    "新建页面失败，请稍后再试",
  );
  const result = response.result;

  return {
    id: result?.documentId ?? "",
    title: result?.title ?? "无标题",
    parent_id: result?.parentId ?? parentId,
    sort_order: result?.sortOrder ?? null,
    workspace_id: result?.workspaceId ?? undefined,
    access_scope: result?.execution?.access_scope ?? "private",
    is_template: result?.execution?.is_template ?? false,
    created_at: result?.execution?.created_at ?? null,
    updated_at: result?.execution?.updated_at ?? result?.updatedAt ?? null,
    meta: {
      requestId: response.requestId,
      traceId: response.traceId,
      commandName: TREE_COMMAND_PROTOCOL.create.preferredCommandName,
    },
  };
}

export async function createChildDocumentCommand(
  input: CreateChildDocumentInput,
): Promise<DocumentCreateChildCommandResult> {
  return postDocumentCommand<DocumentCreateChildCommandResult>(
    "/api/documents/create-child",
    input,
    "创建子页面失败，请稍后再试",
  );
}

export async function renameDocumentCommand(input: RenameDocumentInput): Promise<{ ok: true; meta?: DocumentCommandMeta }> {
  const response = await postTreeCommand<TreeCommandResponse>(
    {
      action: "rename",
      documentId: input.documentId,
      workspaceId: input.workspaceId ?? null,
      title: input.title,
    },
    "重命名失败，请稍后再试",
  );

  return {
    ok: true,
    meta: {
      requestId: response.requestId,
      traceId: response.traceId,
      commandName: TREE_COMMAND_PROTOCOL.rename.preferredCommandName,
    },
  };
}

export async function updatePageTitleCommand(
  input: PageTitleCommandInput,
): Promise<PageHeadCommandResult> {
  return executePageHeadCommand(input);
}

export async function updatePageOptionsCommand(
  input: PageLayoutCommandInput | UpdatePageOptionsInput,
): Promise<PageLayoutCommandResult> {
  const pageOptions = "pageOptions" in input ? input.pageOptions : {};
  return executePageLayoutCommand({
    documentId: input.documentId,
    workspaceId: input.workspaceId ?? null,
    pageOptions,
  });
}

export async function moveDocumentCommand(input: MoveDocumentInput): Promise<{ ok: true; meta?: DocumentCommandMeta }> {
  const response = await postTreeCommand<TreeCommandResponse>(
    {
      action: "move",
      documentId: input.documentId,
      parentId: input.parentId ?? null,
      sortOrder: Number.isFinite(input.position) ? Math.floor(input.position) : 0,
      workspaceId: input.workspaceId ?? null,
    },
    "移动失败，请稍后再试",
  );

  return {
    ok: true,
    meta: {
      requestId: response.requestId,
      traceId: response.traceId,
      commandName: TREE_COMMAND_PROTOCOL.move.preferredCommandName,
    },
  };
}

export async function deleteDocumentCommand(
  input: DeleteDocumentInput,
): Promise<{ success: true; meta?: DocumentCommandMeta }> {
  return postDocumentCommand<{ success: true; meta?: DocumentCommandMeta }>(
    "/api/documents/delete",
    {
      documentId: input.documentId,
      workspaceId: input.workspaceId ?? null,
    },
    "删除失败，请稍后再试",
  );
}

export async function restoreDocumentCommand(
  input: RestoreDocumentInput,
): Promise<{ success: true; meta?: DocumentCommandMeta }> {
  return postDocumentCommand<{ success: true; meta?: DocumentCommandMeta }>(
    "/api/documents/restore",
    {
      documentId: input.documentId,
      workspaceId: input.workspaceId ?? null,
    },
    "恢复失败，请稍后再试",
  );
}

export async function purgeDocumentCommand(
  input: PurgeDocumentInput,
): Promise<{ success: true; purged?: boolean; meta?: DocumentCommandMeta }> {
  return postDocumentCommand<{ success: true; purged?: boolean; meta?: DocumentCommandMeta }>(
    "/api/documents/purge",
    {
      documentId: input.documentId,
    },
    "彻底删除失败，请稍后再试",
  );
}

export async function embedDocumentCommand(
  input: EmbedDocumentInput,
): Promise<{ ok: true; meta?: DocumentCommandMeta }> {
  return postDocumentCommand<{ ok: true; meta?: DocumentCommandMeta }>(
    "/api/documents/embed",
    {
      sourceId: input.sourceId,
      targetId: input.targetId,
    },
    "嵌入失败，请稍后再试",
  );
}

export async function copyTreeCommand(
  input: CopyTreeCommandInput,
): Promise<{
  items: Array<{ oldId: string; newId: string }>;
  meta?: DocumentCommandMeta;
}> {
  return postDocumentCommand<{
    items: Array<{ oldId: string; newId: string }>;
    meta?: DocumentCommandMeta;
  }>(
    "/api/documents/copy-tree",
    {
      targetParentId: input.targetParentId,
      items: input.items,
    },
    "复制页面失败，请稍后再试",
  );
}
