import type { RowDataPacket } from "mysql2";
import { getSessionUser } from "@/lib/auth";
import { ensureOfficialMailSchema, getDbPool } from "@/lib/db";
import { createComposeExitGrant, isComposeExitKey, readComposeExitGrant } from "@/lib/mail-compose-exit-grant";
import { createMailboxMessage } from "@/lib/official-mail";

export const runtime = "nodejs";

export async function GET(request: Request) {
  const user = await getSessionUser();
  const key = new URL(request.url).searchParams.get("key") ?? "";
  if (!user) return Response.json({}, { status: 401 });
  if (!isComposeExitKey(key)) return Response.json({}, { status: 400 });
  return Response.json({ grant: createComposeExitGrant(user.email, key) }, { headers: { "Cache-Control": "private, no-store" } });
}

export async function POST(request: Request) {
  // Accept page-close beacons, but never cross-origin form submissions.
  const origin = request.headers.get("origin");
  let sameOrigin = false;
  try { sameOrigin = Boolean(origin && new URL(origin).host === request.headers.get("host")); } catch { /* Invalid Origin is denied. */ }
  if (!sameOrigin) return Response.json({}, { status: 403 });
  const length = Number(request.headers.get("content-length"));
  if (!Number.isSafeInteger(length) || length < 1 || length > 64 * 1024 * 1024) return Response.json({}, { status: 413 });
  const form = await request.formData();
  const key = String(form.get("exitKey") ?? "");
  if (!isComposeExitKey(key)) return Response.json({}, { status: 400 });
  const user = await getSessionUser();
  const email = user?.email ?? readComposeExitGrant(String(form.get("exitGrant") ?? ""), key);
  if (!email) return Response.json({}, { status: 401 });
  await ensureOfficialMailSchema();
  const connection = await getDbPool().getConnection();
  const lock = `compose-exit:${key}`;
  let acquired = false;
  try {
    const [locks] = await connection.query<(RowDataPacket & { acquired: number })[]>("SELECT GET_LOCK(?, 5) AS acquired", [lock]);
    acquired = Number(locks[0]?.acquired) === 1;
    if (!acquired) return Response.json({}, { status: 409 });
    const messageIdHeader = `<compose-exit-${key}@officialsite.kr>`;
    const [existing] = await connection.query<(RowDataPacket & { id: number | null })[]>(
      `SELECT receipt.mailbox_message_id AS id FROM mailbox_compose_exit_receipts receipt
       INNER JOIN users u ON u.id = receipt.owner_user_id WHERE u.email = ? AND receipt.exit_key = ? LIMIT 1`,
      [email, key],
    );
    if (existing[0]) return Response.json({ saved: true, messageId: existing[0].id });
    const ids = (name: string) => String(form.get(name) ?? "").split(",").map(Number).filter(id => Number.isSafeInteger(id) && id > 0);
    const files = form.getAll("attachmentFiles").filter((entry): entry is File => entry instanceof File && entry.size > 0);
    const result = await createMailboxMessage(email, {
      intent: "draft", deferredDraft: true, messageIdHeader, composeExitKey: key,
      to: String(form.get("to") ?? ""), cc: String(form.get("cc") ?? ""), bcc: String(form.get("bcc") ?? ""),
      subject: String(form.get("subject") ?? ""), body: String(form.get("body") ?? ""), bodyHtml: String(form.get("bodyHtml") ?? ""),
      sourceDraftMessageId: Number(form.get("sourceDraftMessageId")) || null,
      inlineImageUploadIds: ids("inlineImageUploadIds"), attachmentUploadIds: ids("attachmentUploadIds"),
      largeAttachmentUploadIds: ids("largeAttachmentUploadIds"),
      rawAttachmentFiles: await Promise.all(files.map(async file => ({ buffer: Buffer.from(await file.arrayBuffer()), contentType: file.type, filename: file.name, sizeBytes: file.size }))),
    });
    return Response.json({ saved: true, messageId: result.messageId }, { headers: { "Cache-Control": "private, no-store" } });
  } catch (error) {
    console.error("[compose-exit] draft save failed", error instanceof Error ? error.message : "unknown");
    return Response.json({ error: "draft-save-failed" }, { status: 500 });
  } finally {
    if (acquired) await connection.query("SELECT RELEASE_LOCK(?)", [lock]).catch(() => undefined);
    connection.release();
  }
}
