// app/api/inbound-mail/route.ts
//
// Webhook endpoint for an inbound mail routing provider (Mailgun, Postmark,
// SendGrid Inbound Parse, etc). This route is intentionally NOT protected by
// the NextAuth session middleware — it is authenticated instead via HMAC-SHA256
// signature verification against a shared signing key, exactly like the
// provider's own webhook security model expects.
//
// IMPORTANT: this handler reads the raw body text BEFORE any JSON parsing,
// because HMAC signatures are computed over the exact bytes sent — parsing
// and re-serializing JSON would change whitespace/key order and break
// verification.

import { NextRequest, NextResponse } from "next/server";
import { prisma } from "@/lib/prisma";
import { verifyInboundWebhookSignature } from "@/lib/webhook-verify";

const INBOUND_WEBHOOK_SIGNING_KEY = process.env.INBOUND_WEBHOOK_SIGNING_KEY || "";

interface MailgunStyleInboundPayload {
  recipient: string; // target temp email address, e.g. "swift-otter42@mytempdomain.com"
  sender: string; // from address
  subject?: string;
  "body-html"?: string;
  "body-plain"?: string;
  timestamp: string;
  signature: string;
  token?: string;
}

export async function POST(req: NextRequest) {
  try {
    if (!INBOUND_WEBHOOK_SIGNING_KEY) {
      console.error("INBOUND_WEBHOOK_SIGNING_KEY is not configured");
      return NextResponse.json(
        { error: "Server misconfiguration" },
        { status: 500 }
      );
    }

    // Read the raw body ONCE, as text, for signature verification.
    const rawBody = await req.text();
    if (!rawBody) {
      return NextResponse.json({ error: "Empty request body" }, { status: 400 });
    }

    let payload: MailgunStyleInboundPayload;
    try {
      payload = JSON.parse(rawBody);
    } catch {
      return NextResponse.json({ error: "Invalid JSON payload" }, { status: 400 });
    }

    // --- 1. Cryptographic signature verification (HMAC-SHA256) -------------
    const { timestamp, signature } = payload;
    if (!timestamp || !signature) {
      return NextResponse.json(
        { error: "Missing signature or timestamp in payload" },
        { status: 400 }
      );
    }

    // Verify using the raw JSON string representation of just the
    // "signable" fields — here we sign timestamp+token per Mailgun
    // convention. Adjust this composition to match your provider exactly.
    const signableBody = payload.token ? payload.token : rawBody;

    const verification = verifyInboundWebhookSignature(
      signableBody,
      timestamp,
      signature,
      INBOUND_WEBHOOK_SIGNING_KEY
    );

    if (!verification.valid) {
      console.warn("Inbound webhook signature rejected:", verification.reason);
      return NextResponse.json(
        { error: "Signature verification failed" },
        { status: 401 }
      );
    }

    // --- 2. Validate required payload fields --------------------------------
    if (!payload.recipient || typeof payload.recipient !== "string") {
      return NextResponse.json(
        { error: "Payload missing 'recipient' field" },
        { status: 400 }
      );
    }
    if (!payload.sender || typeof payload.sender !== "string") {
      return NextResponse.json(
        { error: "Payload missing 'sender' field" },
        { status: 400 }
      );
    }

    const recipientAddress = payload.recipient.trim().toLowerCase();

    // --- 3. Look up target TempEmail; must exist, be active, and unexpired --
    const now = new Date();
    const tempEmail = await prisma.tempEmail.findUnique({
      where: { address: recipientAddress },
    });

    if (!tempEmail) {
      // Respond 200 so the provider doesn't endlessly retry a message for
      // an address that will never exist — but do not create anything.
      console.info(`Inbound mail dropped: no TempEmail for ${recipientAddress}`);
      return NextResponse.json(
        { status: "dropped", reason: "unknown_recipient" },
        { status: 200 }
      );
    }

    if (!tempEmail.isActive || tempEmail.expiresAt <= now) {
      console.info(`Inbound mail dropped: ${recipientAddress} is expired/inactive`);
      return NextResponse.json(
        { status: "dropped", reason: "expired_or_inactive" },
        { status: 200 }
      );
    }

    // --- 4. Persist the InboundMessage --------------------------------------
    const message = await prisma.inboundMessage.create({
      data: {
        tempEmailId: tempEmail.id,
        fromAddress: payload.sender.trim(),
        subject: (payload.subject || "(no subject)").slice(0, 500),
        bodyHtml: payload["body-html"] || "",
        bodyText: payload["body-plain"] || "",
        receivedAt: now,
      },
    });

    return NextResponse.json(
      { status: "accepted", messageId: message.id },
      { status: 200 }
    );
  } catch (err) {
    console.error("POST /api/inbound-mail failed:", err);
    return NextResponse.json(
      { error: "Internal error processing inbound mail" },
      { status: 500 }
    );
  }
}
