import { NextRequest, NextResponse } from "next/server";
import { z } from "zod";
import { stripe } from "@/lib/stripe";
import { prisma } from "@/lib/db";
import { TIERS, priceForRegion, TierId } from "@/lib/tiers";
import { REGION_BY_ID } from "@/lib/regions";
import { rateLimit, getClientIp } from "@/lib/rate-limit";
import { sanitizeForDisplay, safeUrl } from "@/lib/sanitize";

export const runtime = "nodejs";

const Body = z.object({
  regionId: z.string().min(1).max(100),
  tierId: z.string().min(1).max(50),
  message: z.string().min(1).max(60),
  donorName: z.string().max(120).nullable(),
  donorEmail: z.string().email().max(200),
  websiteUrl: z.string().max(500).nullable(),
  isAnonymous: z.boolean(),
});

export async function POST(req: NextRequest) {
  const ip = getClientIp(req.headers);
  const rl = rateLimit(ip);
  if (!rl.allowed) {
    return NextResponse.json(
      { error: "Too many attempts. Please wait a minute and try again." },
      { status: 429 },
    );
  }

  let body;
  try {
    body = Body.parse(await req.json());
  } catch (e) {
    return NextResponse.json({ error: "Invalid request" }, { status: 400 });
  }

  const tierId = body.tierId as TierId;
  if (!(tierId in TIERS)) {
    return NextResponse.json({ error: "Unknown tier" }, { status: 400 });
  }

  // Naming rights special case: virtual region.
  if (tierId === "naming-rights") {
    if (body.regionId !== "naming-rights") {
      return NextResponse.json({ error: "Bad region" }, { status: 400 });
    }
    const settings = await prisma.settings.findUnique({ where: { id: 1 } });
    if (settings?.namingRightsClaimed) {
      return NextResponse.json(
        { error: "Naming rights have already been claimed." },
        { status: 409 },
      );
    }
  } else {
    const region = REGION_BY_ID[body.regionId];
    if (!region || region.tier !== tierId) {
      return NextResponse.json(
        { error: "Region not found or tier mismatch" },
        { status: 400 },
      );
    }
    // Check if already claimed (approved or pending recent).
    const existing = await prisma.donation.findFirst({
      where: {
        regionId: body.regionId,
        status: { in: ["APPROVED", "PENDING"] },
      },
      orderBy: { createdAt: "desc" },
    });
    if (existing) {
      return NextResponse.json(
        {
          error: `This piece has already been donated. Please choose another.`,
        },
        { status: 409 },
      );
    }
  }

  const amountCents = priceForRegion(body.regionId, tierId);

  // Sanitize text BEFORE persisting.
  const cleanMessage = sanitizeForDisplay(body.message);
  const cleanWebsite = safeUrl(body.websiteUrl);
  if (body.websiteUrl && !cleanWebsite) {
    return NextResponse.json(
      { error: "Website URL is invalid" },
      { status: 400 },
    );
  }

  let pi;
  try {
    pi = await stripe.paymentIntents.create({
      amount: amountCents,
      currency: "usd",
      automatic_payment_methods: { enabled: true },
      receipt_email: body.donorEmail,
      description: `PIFF — ${TIERS[tierId].label}`,
      metadata: {
        regionId: body.regionId,
        tierId,
      },
    });
  } catch (err) {
    return NextResponse.json(
      { error: "Could not create payment. Check Stripe configuration." },
      { status: 500 },
    );
  }

  // Persist donation in PENDING; webhook will mark payment confirmed.
  const donation = await prisma.donation.create({
    data: {
      stripePaymentIntentId: pi.id,
      regionId: body.regionId,
      tierId,
      amountCents,
      donorName: body.isAnonymous ? body.donorName : body.donorName,
      donorEmail: body.donorEmail,
      isAnonymous: body.isAnonymous,
      message: cleanMessage,
      websiteUrl: cleanWebsite,
      status: "PENDING",
    },
  });

  return NextResponse.json({
    clientSecret: pi.client_secret,
    donationId: donation.id,
  });
}
