import { getSessionUser } from "@/lib/auth";
import {
  createMailboxFolderByEmail,
  createMailboxSenderMoveRuleByEmail,
  enqueueMailboxMessagesMoveByEmail,
  getMailboxSenderMoveRuleForMessagesByEmail,
  getMailboxSpamRuleSettingsByEmail,
  refreshMailboxByEmail,
  resolveMailboxMessageIdsByRemoteUids
} from "@/lib/official-mail";

type MoveMailboxPayload = {
  continueMove?: boolean;
  expectedExistingTargetFolder?: string;
  messageIds?: Array<number | string>;
  moveExistingMessages?: boolean;
  newFolderName?: string;
  replaceExistingRule?: boolean;
  remoteUids?: Array<number | string>;
  remoteRefs?: Array<{ folder: string; uid: number | string }>;
  releaseSpam?: boolean;
  sourceFolder?: string;
  targetFolder?: string;
};

function parseMessageIds(payload: MoveMailboxPayload) {
  return (payload.messageIds ?? [])
    .map((value) => Number(value))
    .filter((value) => Number.isInteger(value) && value > 0);
}

export async function POST(request: Request) {
  const user = await getSessionUser();

  if (!user) {
    return Response.json({ error: "unauthorized", ok: false }, { status: 401 });
  }

  const payload = (await request.json().catch(() => null)) as MoveMailboxPayload | null;
  let messageIds = parseMessageIds(payload ?? {});
  const remoteUids = parseMessageIds({ messageIds: payload?.remoteUids });
  const sourceFolder = String(payload?.sourceFolder ?? "inbox").trim() || "inbox";
  const rawRemoteRefs = payload?.remoteRefs ?? [];
  if (!Array.isArray(rawRemoteRefs) || rawRemoteRefs.some((ref) =>
    !ref || typeof ref !== "object" ||
    (typeof ref.folder !== "string" || !(/^(inbox|sent|drafts|spam|trash|custom__[a-zA-Z0-9_-]+)$/.test(ref.folder))) ||
    !Number.isSafeInteger(Number(ref.uid)) || Number(ref.uid) <= 0
  ) || (rawRemoteRefs.length > 0 && sourceFolder !== "all")) {
    return Response.json({ error: "invalid-remote-references", ok: false }, { status: 400 });
  }
  const remoteRefs = [...new Map(rawRemoteRefs.map((ref) => [
    `${ref.folder}:${Number(ref.uid)}`,
    { folder: ref.folder, uid: Number(ref.uid) }
  ])).values()];
  let targetFolder = String(payload?.targetFolder ?? "").trim();
  const newFolderName = String(payload?.newFolderName ?? "").trim();

  try {
    if (messageIds.length === 0 && remoteUids.length > 0) {
      messageIds = await resolveMailboxMessageIdsByRemoteUids(user.email, remoteUids, sourceFolder);

      if (messageIds.length !== remoteUids.length) {
        await refreshMailboxByEmail(user.email, { folder: sourceFolder });
        messageIds = await resolveMailboxMessageIdsByRemoteUids(user.email, remoteUids, sourceFolder);
      }
    }
    if (remoteRefs.length > 0) {
      const refsByFolder = new Map<string, number[]>();
      for (const ref of remoteRefs) {
        const uids = refsByFolder.get(ref.folder) ?? [];
        uids.push(ref.uid);
        refsByFolder.set(ref.folder, uids);
      }
      for (const [folder, uids] of refsByFolder) {
        let resolved = await resolveMailboxMessageIdsByRemoteUids(user.email, uids, folder);
        if (resolved.length !== uids.length) {
          await refreshMailboxByEmail(user.email, { folder });
          resolved = await resolveMailboxMessageIdsByRemoteUids(user.email, uids, folder);
        }
        if (resolved.length !== uids.length) {
          return Response.json(
            {
              error: "message-not-found",
              message: "이동할 메일을 찾지 못했습니다. 새로고침 후 다시 시도해주세요.",
              ok: false
            },
            { status: 409 }
          );
        }
        messageIds.push(...resolved);
      }
      messageIds = [...new Set(messageIds)];
    }
  } catch {
    return Response.json(
      {
        error: "move-sync-failed",
        message: "메일 상태를 동기화하지 못했습니다. 새로고침 후 다시 시도해주세요.",
        notice: {
          message: "메일 상태를 동기화하지 못했습니다. 새로고침 후 다시 시도해주세요.",
          tone: "error"
        },
        ok: false
      },
      { status: 409 }
    );
  }

  if (remoteUids.length > 0 && messageIds.length !== remoteUids.length) {
    return Response.json(
      {
        error: "message-not-found",
        message: "이동할 메일을 찾지 못했습니다. 새로고침 후 다시 시도해주세요.",
        notice: {
          message: "이동할 메일을 찾지 못했습니다. 새로고침 후 다시 시도해주세요.",
          tone: "error"
        },
        ok: false
      },
      { status: 409 }
    );
  }

  if (messageIds.length === 0) {
    return Response.json(
      {
        error: "message-required",
        message: "이동할 메일을 먼저 선택해 주세요.",
        notice: { message: "이동할 메일을 먼저 선택해 주세요.", tone: "error" },
        ok: false
      },
      { status: 400 }
    );
  }

  if ((!targetFolder || targetFolder === "__new__") && !newFolderName) {
    return Response.json(
      {
        error: "target-folder-required",
        message: "이동할 메일함을 선택해 주세요.",
        notice: { message: "이동할 메일함을 선택해 주세요.", tone: "error" },
        ok: false
      },
      { status: 400 }
    );
  }

  try {
    if (payload?.continueMove && !payload.replaceExistingRule) {
      const existingRule = await getMailboxSenderMoveRuleForMessagesByEmail(user.email, messageIds);
      const requestsDifferentTarget =
        existingRule && (targetFolder === "__new__" || existingRule.targetFolderSystemName !== targetFolder);

      if (requestsDifferentTarget) {
        return Response.json(
          {
            error: "continue-move-rule-exists",
            existingTargetFolder: existingRule.targetFolderSystemName,
            message: "동일한 발신자의 자동분류 규칙이 이미 있습니다. 기존 규칙을 변경할지 확인해주세요.",
            notice: {
              message: "동일한 발신자의 자동분류 규칙이 이미 있습니다. 기존 규칙을 변경할지 확인해주세요.",
              tone: "error"
            },
            ok: false
          },
          { status: 409 }
        );
      }
    }

    if ((!targetFolder || targetFolder === "__new__") && newFolderName) {
      const createdFolder = await createMailboxFolderByEmail(user.email, newFolderName);
      targetFolder = createdFolder.systemName;
    }

    if (!payload?.continueMove) {
      const spamSettings = targetFolder === "spam" && !payload?.releaseSpam
        ? (await getMailboxSpamRuleSettingsByEmail(user.email)).general
        : null;
      const job = await enqueueMailboxMessagesMoveByEmail(user.email, messageIds, targetFolder, {
        releaseSpam: Boolean(payload?.releaseSpam),
        sourceFolder
      });
      const noticeMessage = payload?.releaseSpam
        ? "선택한 메일을 받은메일함으로 이동하고 스팸 분류를 해제합니다."
        : targetFolder === "spam"
          ? spamSettings?.reportedMessageAction === "delete"
            ? "선택한 메일을 영구 삭제합니다."
            : spamSettings?.processPreviousReported
              ? "선택한 발신자의 메일을 스팸으로 이동합니다."
              : "선택한 메일을 스팸으로 이동합니다."
          : targetFolder === "trash"
            ? "선택한 메일을 휴지통으로 이동합니다."
            : "선택한 메일을 폴더로 이동합니다.";

      return Response.json(
        {
          jobId: job.id,
          notice: { message: noticeMessage, tone: "success" },
          ok: true,
          queued: true
        },
        { status: 202 }
      );
    }

    const result = await createMailboxSenderMoveRuleByEmail(user.email, messageIds, targetFolder, {
      expectedExistingTargetFolder: payload.expectedExistingTargetFolder,
      moveExistingMessages: Boolean(payload.moveExistingMessages),
      replaceExistingRule: Boolean(payload.replaceExistingRule),
      sourceFolder
    });
    const noticeMessage =
      targetFolder === "inbox"
        ? payload.moveExistingMessages
          ? "기존 자동분류를 해제하고 같은 발신자의 기존 메일을 받은메일함으로 이동했습니다."
          : "기존 자동분류를 해제하고 선택한 메일을 받은메일함으로 이동했습니다."
        : payload.moveExistingMessages
          ? "앞으로 수신되는 메일과 기존 받은 메일을 선택한 메일함으로 이동했습니다."
          : "앞으로 같은 발신자에게 오는 메일을 선택한 메일함으로 이동합니다.";

    return Response.json({
      jobId: result.jobId,
      notice: {
        message: noticeMessage,
        tone: "success"
      },
      ok: true,
      queued: result.queued,
      result
    }, { status: result.queued ? 202 : 200 });
  } catch (error) {
    const detailMessage = error instanceof Error ? error.message : "move-failed";
    const existingTargetFolder = detailMessage.startsWith("continue-move-rule-exists:")
      ? detailMessage.slice("continue-move-rule-exists:".length)
      : null;
    const errorCode = existingTargetFolder
      ? "continue-move-rule-exists"
      : detailMessage === "sent-folder-only-outbound"
        ? "move-sent-only"
        : detailMessage === "continue-move-custom-folder-only"
          ? "continue-move-custom-folder-only"
          : detailMessage === "continue-move-rule-not-found"
            ? "continue-move-rule-not-found"
            : detailMessage === "continue-move-requires-one-sender"
              ? "continue-move-requires-one-sender"
              : detailMessage === "continue-move-rule-limit"
                ? "continue-move-rule-limit"
                : detailMessage === "folder-name-exists"
                  ? "folder-name-exists"
                  : detailMessage === "mailbox-move-failed" ||
                      detailMessage === "mailbox-delete-failed" ||
                      detailMessage === "mailbox-busy" ||
                      detailMessage === "mailbox-state-changed" ||
                      detailMessage.includes("Duplicate entry")
                    ? "move-conflict"
                    : "move-failed";
    const errorMessage =
      errorCode === "continue-move-rule-exists"
        ? "동일한 발신자의 자동분류 규칙이 이미 있습니다. 기존 규칙을 변경할지 확인해주세요."
        : errorCode === "move-sent-only"
          ? "보낸 메일만 보낸메일함으로 이동할 수 있습니다."
          : errorCode === "continue-move-custom-folder-only"
            ? "계속 이동은 받은메일함 또는 내 메일함을 선택했을 때 설정할 수 있습니다."
            : errorCode === "continue-move-rule-not-found"
              ? "이 발신자에 등록된 자동분류가 없습니다. 일반 이동을 이용해 주세요."
              : errorCode === "continue-move-requires-one-sender"
                ? "계속 이동은 같은 발신자의 받은 메일만 선택해 설정할 수 있습니다."
                : errorCode === "continue-move-rule-limit"
                  ? "자동분류 규칙은 최대 1,000개까지 등록할 수 있습니다."
                  : errorCode === "folder-name-exists"
                    ? "같은 이름의 메일함이 이미 있습니다."
                    : errorCode === "move-conflict"
                      ? "메일 상태가 최신이 아니어서 이동에 실패했습니다. 메일함을 다시 연 뒤 다시 시도해 주세요."
                      : "메일 이동 중 오류가 발생했습니다.";

    return Response.json(
      {
        error: errorCode,
        existingTargetFolder,
        message: errorMessage,
        notice: {
          message: errorMessage,
          tone: "error"
        },
        ok: false
      },
      {
        status:
          errorCode === "continue-move-rule-exists"
            ? 409
            : errorCode === "move-sent-only" ||
                errorCode === "continue-move-custom-folder-only" ||
                errorCode === "continue-move-rule-not-found" ||
                errorCode === "continue-move-requires-one-sender" ||
                errorCode === "continue-move-rule-limit" ||
                errorCode === "folder-name-exists"
              ? 400
              : errorCode === "move-conflict"
                ? 409
                : 500
      }
    );
  }
}
