import { cookies } from "next/headers";
import {
  getAuthRequestMetadata,
  recordUserAuthActivity,
} from "@/lib/auth-activity";
import { saveSessionUser } from "@/lib/auth";
import {
  buildMailEntryUrl,
  resolveMailAppUrlFromHeaders,
} from "@/lib/mail-urls";
import {
  createPendingSignupRegistration,
  expediteMailboxProvisioningRecoveryJob,
  finalizePendingSignupRegistration,
  type PendingSignupRegistration,
  type SignupProvisioningProgress,
} from "@/lib/official-mail";
import {
  MARKETING_VISITOR_COOKIE,
  recordMarketingLifecycleEvent,
} from "@/lib/marketing-analytics";

export const runtime = "nodejs";
export const dynamic = "force-dynamic";

type SignupRequestBody = {
  companyName?: string;
  domain?: string;
  localPart?: string;
  password?: string;
  passwordConfirm?: string;
  recoveryEmail?: string;
  recoveryVerificationId?: number;
  recoveryVerificationToken?: string;
  termsAccepted?: boolean;
};

type SignupStreamChunk =
  | {
      description: string;
      status: "running" | "complete";
      step: SignupProvisioningProgress["step"];
      title: string;
      type: "progress";
    }
  | {
      redirectUrl: string;
      type: "complete";
    }
  | {
      error: string;
      message: string;
      redirectUrl?: string;
      type: "error";
    };

function streamChunk(value: SignupStreamChunk) {
  return `${JSON.stringify(value)}\n`;
}

function extractMailcowDetail(message: string) {
  const [prefix, ...rest] = message.split(":");

  if (
    !prefix.startsWith("mailcow-") &&
    !prefix.startsWith("snapshot-load-failed") &&
    !prefix.startsWith("user-load-failed")
  ) {
    return "";
  }

  return rest.join(":").trim().slice(0, 240);
}

function mapSignupError(error: unknown) {
  if (!(error instanceof Error)) {
    return {
      details: "",
      error: "system",
      message: "회원가입 처리 중 오류가 발생했습니다.",
      status: 500,
    };
  }

  if (error.message === "required") {
    return {
      details: "",
      error: "required",
      message:
        "사업자명, 도메인, 대표 메일 아이디, 비밀번호, 보조 이메일을 모두 입력해주세요.",
      status: 400,
    };
  }

  if (error.message === "company-name-too-long") {
    return {
      details: "",
      error: "company-name-too-long",
      message: "사업자명은 191자 이내로 입력해주세요.",
      status: 400,
    };
  }

  if (error.message === "domain-too-long") {
    return {
      details: "",
      error: "domain-too-long",
      message: "도메인과 생성될 메일 주소가 너무 깁니다. 도메인 값을 확인해주세요.",
      status: 400,
    };
  }

  if (error.message === "password-mismatch") {
    return {
      details: "",
      error: "password-mismatch",
      message: "비밀번호 확인이 일치하지 않습니다.",
      status: 400,
    };
  }

  if (error.message.startsWith("mailcow-password-policy:")) {
    const minLength = Number(error.message.split(":")[1]) || 6;

    return {
      details: "",
      error: "password-policy",
      message: `비밀번호는 최소 ${minLength}자 이상 입력해주세요.`,
      status: 400,
    };
  }

  if (error.message === "mailcow-password-policy-unavailable") {
    return {
      details: "",
      error: "mail-config",
      message: "메일 서버 비밀번호 정책을 확인하지 못했습니다. 잠시 후 다시 시도해주세요.",
      status: 502,
    };
  }

  if (error.message === "terms-required") {
    return {
      details: "",
      error: "terms-required",
      message: "이용약관 및 개인정보처리방침에 동의해주세요.",
      status: 400,
    };
  }

  if (error.message === "email-exists") {
    return {
      details: "",
      error: "email-exists",
      message:
        "이미 등록된 대표 메일 주소입니다. 로그인 또는 비밀번호 재설정을 이용해주세요.",
      status: 409,
    };
  }

  if (error.message === "domain-taken") {
    return {
      details: "",
      error: "domain-taken",
      message: "이미 다른 계정에서 사용 중인 도메인입니다.",
      status: 409,
    };
  }

  if (error.message === "domain-recovery-owner-mismatch") {
    return {
      details: "",
      error: "domain-recovery-owner-mismatch",
      message: "이 도메인은 이전 가입에 사용한 대표 메일 주소로만 복구할 수 있습니다.",
      status: 409,
    };
  }

  if (error.message === "domain-recovery-verification-required") {
    return {
      details: "",
      error: "domain-recovery-verification-required",
      message: "이 도메인을 복구하려면 이전 가입에 사용한 보조 이메일 인증이 필요합니다.",
      status: 409,
    };
  }

  if (error.message.startsWith("domain-www-prefix:")) {
    const suggestion = error.message.slice("domain-www-prefix:".length).trim();

    return {
      details: "",
      error: "domain-www-prefix",
      message: `www를 제외한 도메인으로 입력해주세요. 예: ${suggestion || "officialsite.kr"}`,
      status: 400,
    };
  }

  if (error.message === "invalid-domain") {
    return {
      details: "",
      error: "invalid-domain",
      message:
        "구매하신 도메인 주소 형식으로 입력해주세요. 예: officialsite.kr",
      status: 400,
    };
  }

  if (error.message === "invalid-local-part") {
    return {
      details: "",
      error: "invalid-local-part",
      message:
        "대표 메일 아이디는 영문 소문자, 숫자, 점(.), 하이픈(-), 밑줄(_)만 사용할 수 있습니다.",
      status: 400,
    };
  }

  if (error.message === "recovery-email-required") {
    return {
      details: "",
      error: "recovery-email-required",
      message: "보조 이메일을 입력해주세요.",
      status: 400,
    };
  }

  if (error.message === "recovery-email-invalid") {
    return {
      details: "",
      error: "recovery-email-invalid",
      message: "보조 이메일 형식이 올바르지 않습니다.",
      status: 400,
    };
  }

  if (error.message === "recovery-email-unverified") {
    return {
      details: "",
      error: "recovery-email-unverified",
      message: "보조 이메일 인증을 완료해야 회원가입할 수 있습니다.",
      status: 400,
    };
  }

  if (error.message === "recovery-email-expired") {
    return {
      details: "",
      error: "recovery-email-expired",
      message: "보조 이메일 인증이 만료되었습니다. 인증번호를 다시 받아주세요.",
      status: 400,
    };
  }

  if (
    error.message === "mailcow-config-missing" ||
    error.message === "mailcow-config-invalid"
  ) {
    return {
      details: "",
      error: "mail-config",
      message: "메일 서버 설정값이 올바르지 않습니다.",
      status: 500,
    };
  }

  if (error.message === "mailcow-auth-failed") {
    return {
      details: "",
      error: "mail-auth",
      message: "메일 서버 API 인증에 실패했습니다.",
      status: 502,
    };
  }

  if (error.message === "mailcow-domain-exists") {
    return {
      details: "",
      error: "mail-domain-exists",
      message: "메일 서버에 이미 같은 도메인이 있어 자동 연결하지 못했습니다.",
      status: 409,
    };
  }

  if (
    error.message.startsWith("mailcow-provisioning-failed:") ||
    error.message.startsWith("mailcow-request-failed:")
  ) {
    return {
      details: extractMailcowDetail(error.message),
      error: "mail-setup",
      message: "메일 서버 생성 중 오류가 발생했습니다.",
      status: 502,
    };
  }

  return {
    details: extractMailcowDetail(error.message),
    error: "system",
    message: "회원가입 처리 중 오류가 발생했습니다.",
    status: 500,
  };
}

export async function POST(request: Request) {
  const mailAppUrl = resolveMailAppUrlFromHeaders(request.headers);
  const visitorId = (await cookies()).get(MARKETING_VISITOR_COOKIE)?.value ?? null;
  let body: SignupRequestBody | null = null;

  try {
    body = await request.json();
  } catch {
    return Response.json(
      {
        error: "invalid-json",
        message: "회원가입 요청 형식이 올바르지 않습니다.",
      },
      { status: 400 },
    );
  }

  const password = body?.password?.trim() ?? "";
  const passwordConfirm = body?.passwordConfirm?.trim() ?? "";

  if (password !== passwordConfirm) {
    const mapped = mapSignupError(new Error("password-mismatch"));
    return Response.json(
      {
        details: mapped.details,
        error: mapped.error,
        message: mapped.message,
      },
      { status: mapped.status },
    );
  }

  if (body?.termsAccepted !== true) {
    const mapped = mapSignupError(new Error("terms-required"));
    return Response.json(
      {
        details: mapped.details,
        error: mapped.error,
        message: mapped.message,
      },
      { status: mapped.status },
    );
  }

  let pending: PendingSignupRegistration;

  try {
    pending = await createPendingSignupRegistration({
      companyName: body?.companyName ?? "",
      domain: body?.domain ?? "",
      localPart: body?.localPart ?? "owner",
      password,
      recoveryEmail: body?.recoveryEmail ?? "",
      recoveryVerificationId: Number(body?.recoveryVerificationId ?? 0),
      recoveryVerificationToken: body?.recoveryVerificationToken ?? "",
      termsAccepted: body.termsAccepted,
    });
  } catch (error) {
    const mapped = mapSignupError(error);

    return Response.json(
      {
        details: mapped.details,
        error: mapped.error,
        message: mapped.message,
      },
      { status: mapped.status },
    );
  }

  await recordMarketingLifecycleEvent({
    domainId: pending.domainId,
    eventType: "signup_completed",
    userId: pending.userId,
    visitorId,
  });
  await saveSessionUser(pending.snapshot);
  await recordUserAuthActivity({
    ...getAuthRequestMetadata(request.headers, "web"),
    eventType: "login",
    identityEmail: pending.snapshot.email,
    lookup: "login_email",
    outcome: "success",
  });

  const encoder = new TextEncoder();
  const stream = new ReadableStream<Uint8Array>({
    start(controller) {
      let closed = false;

      const send = (payload: SignupStreamChunk) => {
        if (closed) {
          return;
        }

        controller.enqueue(encoder.encode(streamChunk(payload)));
      };

      const close = () => {
        if (closed) {
          return;
        }

        closed = true;

        try {
          controller.close();
        } catch {
          // Ignore duplicate close calls caused by abort races.
        }
      };

      void (async () => {
        send({
          type: "progress",
          step: "account",
          status: "complete",
          title: "대표 계정 생성 완료",
          description: `${pending.snapshot.email} 계정과 기본 메일함을 먼저 만들었습니다.`,
        });

        try {
          const snapshot = await finalizePendingSignupRegistration(pending, {
            onProgress(progress) {
              send({ type: "progress", ...progress });
            },
          });

          send({
            type: "complete",
            redirectUrl: buildMailEntryUrl(snapshot, mailAppUrl),
          });
        } catch (error) {
          console.error("Signup provisioning deferred to recovery worker", error);

          try {
            await expediteMailboxProvisioningRecoveryJob(pending.mailboxId, error);
          } catch (recoveryError) {
            console.error("Signup provisioning recovery scheduling failed", recoveryError);
          }

          send({
            type: "complete",
            redirectUrl: buildMailEntryUrl(pending.snapshot, mailAppUrl),
          });
        } finally {
          close();
        }
      })();

      request.signal.addEventListener("abort", close, { once: true });
    },
  });

  return new Response(stream, {
    headers: {
      "Cache-Control": "no-cache, no-transform",
      "Content-Type": "application/x-ndjson; charset=utf-8",
      "X-Accel-Buffering": "no",
    },
  });
}
