"use client";

import type { MediaAsset } from "@/types/media";
import type {
  FileTreeShellDeletePreflightPayload,
  FileTreeShellInternalDropPreflightPayload,
  FileTreeShellPastePreflightPayload,
  FileTreeShellUploadTargetPreflightPayload,
} from "@/lib/file-tree/shell";

type ResourceCommandAction = "copy" | "move" | "rename" | "delete" | "restore";

type ResourceCommandErrorPayload = {
  error?: string;
};

type ResourceCommandResponse = {
  ok?: boolean;
  items?: MediaAsset[];
  asset?: MediaAsset;
};

type TransferResourceAssetsInput = {
  assetIds: readonly string[];
  targetDocumentId: string;
  targetSubPath?: string | null;
};

type RenameResourceAssetInput = {
  assetId: string;
  newName: string;
};

type UploadResourceAssetInput = {
  file: File;
  workspaceId: string;
  documentId: string;
  mindmapId?: string | null;
};

export type FileTreeInternalDropPreflightPlan = {
  copy: boolean;
  targetDocumentId: string;
  targetMindmapId: string | null;
  targetSubPath?: string | null;
  rowIds: string[];
  docIds: string[];
  topLevelDocIds: string[];
  copyableAssetIds: string[];
  sourceAssetDocumentIds: string[];
  documentTransferPlan?: {
    action: "copy" | "move";
    targetParentId: string;
    documentIds: string[];
    topLevelDocumentIds: string[];
    copyItems: Array<{ documentId: string; recursive: boolean }>;
  } | null;
  resourceTransferPlan?: {
    action: "copy" | "move";
    assetIds: string[];
    targetDocumentId: string;
    targetSubPath?: string | null;
  } | null;
};

type FileTreeInternalDropPreflightResponse = {
  plan?: FileTreeInternalDropPreflightPlan;
};

export type FileTreeDeletePreflightPlan = {
  rowIds: string[];
  docIds: string[];
  assetIds: string[];
  assetDocumentIds: string[];
};

type FileTreeDeletePreflightResponse = {
  plan?: FileTreeDeletePreflightPlan;
};

export type FileTreePastePreflightPlan = {
  targetDocumentId: string;
  targetMindmapId: string | null;
  targetSubPath?: string | null;
  rowIds: string[];
  docItems: Array<{ documentId: string; recursive: boolean }>;
  copyableAssetIds: string[];
  resourceTransferPlan?: {
    action: "copy";
    assetIds: string[];
    targetDocumentId: string;
    targetSubPath?: string | null;
  } | null;
};

type FileTreePastePreflightResponse = {
  plan?: FileTreePastePreflightPlan;
};

export type FileTreeUploadTargetPreflightPlan = {
  workspaceId: string;
  targetDocumentId: string;
  targetMindmapId: string | null;
  targetSubPath?: string | null;
};

type FileTreeUploadTargetPreflightResponse = {
  plan?: FileTreeUploadTargetPreflightPlan;
};

function normalizeAssetIds(assetIds: readonly string[]): string[] {
  return Array.from(
    new Set(
      assetIds
        .map((assetId) => (typeof assetId === "string" ? assetId.trim() : ""))
        .filter(Boolean),
    ),
  );
}

async function postResourceCommand<TResult>(
  payload: Record<string, unknown>,
  fallbackMessage: string,
  path = "/api/media/batch",
): 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
    | ResourceCommandErrorPayload
    | 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;
}

async function postResourceForm<TResult>(
  path: string,
  formData: FormData,
  fallbackMessage: string,
): Promise<TResult> {
  const response = await fetch(path, {
    method: "POST",
    body: formData,
  });

  const body = (await response.json().catch(() => null)) as
    | TResult
    | ResourceCommandErrorPayload
    | 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;
}

function buildTransferPayload(
  action: Extract<ResourceCommandAction, "copy" | "move">,
  input: TransferResourceAssetsInput,
) {
  const payload: Record<string, unknown> = {
    action,
    assetIds: normalizeAssetIds(input.assetIds),
    targetDocumentId: input.targetDocumentId,
  };
  const targetSubPath = input.targetSubPath?.trim();
  if (targetSubPath) {
    payload.targetSubPath = targetSubPath;
  }
  return payload;
}

export async function copyFileTreeResourceAssets(
  input: TransferResourceAssetsInput,
): Promise<ResourceCommandResponse> {
  return postResourceCommand<ResourceCommandResponse>(
    buildTransferPayload("copy", input),
    "复制附件失败",
  );
}

export async function moveFileTreeResourceAssets(
  input: TransferResourceAssetsInput,
): Promise<ResourceCommandResponse> {
  return postResourceCommand<ResourceCommandResponse>(
    buildTransferPayload("move", input),
    "移动附件失败",
  );
}

export async function renameFileTreeResourceAsset(
  input: RenameResourceAssetInput,
): Promise<ResourceCommandResponse> {
  return postResourceCommand<ResourceCommandResponse>(
    {
      action: "rename",
      assetIds: normalizeAssetIds([input.assetId]),
      newName: input.newName,
    },
    "重命名失败",
  );
}

export async function deleteFileTreeResourceAssets(
  assetIds: readonly string[],
): Promise<ResourceCommandResponse> {
  return postResourceCommand<ResourceCommandResponse>(
    {
      action: "delete",
      assetIds: normalizeAssetIds(assetIds),
    },
    "删除失败",
  );
}

export async function restoreFileTreeResourceAssets(
  assetIds: readonly string[],
): Promise<ResourceCommandResponse> {
  return postResourceCommand<ResourceCommandResponse>(
    {
      action: "restore",
      assetIds: normalizeAssetIds(assetIds),
    },
    "恢复附件失败，请稍后再试",
  );
}

export async function uploadFileTreeResourceAsset(
  input: UploadResourceAssetInput,
): Promise<ResourceCommandResponse> {
  const formData = new FormData();
  formData.append("file", input.file);
  formData.append("workspaceId", input.workspaceId);
  formData.append("documentId", input.documentId);
  const mindmapId = input.mindmapId?.trim();
  if (mindmapId) {
    formData.append("mindmapId", mindmapId);
  }
  return postResourceForm<ResourceCommandResponse>(
    "/api/media/upload",
    formData,
    "上传失败",
  );
}

export async function preflightFileTreeInternalDrop(
  input: FileTreeShellInternalDropPreflightPayload,
): Promise<FileTreeInternalDropPreflightPlan> {
  const response = await postResourceCommand<FileTreeInternalDropPreflightResponse>(
    input,
    "文件树拖放预检失败",
    "/api/tree/filetree/drop-preflight",
  );
  if (!response.plan) {
    throw new Error("文件树拖放预检失败");
  }
  return response.plan;
}

export async function preflightFileTreeDelete(
  input: FileTreeShellDeletePreflightPayload,
): Promise<FileTreeDeletePreflightPlan> {
  const response = await postResourceCommand<FileTreeDeletePreflightResponse>(
    input,
    "文件树删除预检失败",
    "/api/tree/filetree/delete-preflight",
  );
  if (!response.plan) {
    throw new Error("文件树删除预检失败");
  }
  return response.plan;
}

export async function preflightFileTreePaste(
  input: FileTreeShellPastePreflightPayload,
): Promise<FileTreePastePreflightPlan> {
  const response = await postResourceCommand<FileTreePastePreflightResponse>(
    input,
    "文件树粘贴预检失败",
    "/api/tree/filetree/paste-preflight",
  );
  if (!response.plan) {
    throw new Error("文件树粘贴预检失败");
  }
  return response.plan;
}

export async function preflightFileTreeUploadTarget(
  input: FileTreeShellUploadTargetPreflightPayload,
): Promise<FileTreeUploadTargetPreflightPlan> {
  const response = await postResourceCommand<FileTreeUploadTargetPreflightResponse>(
    input,
    "文件树上传目标预检失败",
    "/api/tree/filetree/upload-target-preflight",
  );
  if (!response.plan) {
    throw new Error("文件树上传目标预检失败");
  }
  return response.plan;
}
