import { NextRequest, NextResponse } from "next/server";
import { auth } from "@/auth";
import { db } from "@/lib/db";
import { getStripeClient } from "@/lib/stripe";

type CartItem = {
  productId: string;
  name: string;
  price: number;
  quantity: number;
  image: string;
  variationId?: string;
};

type CheckoutBody = {
  items: CartItem[];
  contact: {
    name: string;
    email: string;
    phone?: string;
  };
  shipping: {
    address: string;
    city: string;
    state: string;
    zip: string;
    country: string;
  };
};

export async function POST(req: NextRequest) {
  const session = await auth();

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

  const { items, contact, shipping } = body;

  if (!items?.length || !contact?.name || !contact?.email || !shipping?.address) {
    return NextResponse.json({ error: "Missing required fields." }, { status: 400 });
  }

  // Validate email format
  if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(contact.email)) {
    return NextResponse.json({ error: "Invalid email address." }, { status: 400 });
  }

  // Verify products exist and are active
  const productIds = [...new Set(items.map(i => i.productId))];
  const dbProducts = await db.product.findMany({
    where: { id: { in: productIds }, isActive: true },
    include: { images: { where: { isPrimary: true }, take: 1 } },
  });

  if (dbProducts.length !== productIds.length) {
    return NextResponse.json({ error: "One or more products are unavailable." }, { status: 400 });
  }

  // Calculate total from DB prices (server-side validation)
  const total = items.reduce((sum, item) => {
    const dbProduct = dbProducts.find(p => p.id === item.productId);
    if (!dbProduct) return sum;
    return sum + Number(dbProduct.price) * item.quantity;
  }, 0);

  const stripe = await getStripeClient();

  // Create Stripe Payment Intent
  const paymentIntent = await stripe.paymentIntents.create({
    amount: Math.round(total * 100), // cents
    currency: "usd",
    metadata: {
      customerName: contact.name,
      customerEmail: contact.email,
      userId: session?.user?.id ?? "guest",
    },
  });

  // Create pending order in DB
  const order = await db.order.create({
    data: {
      userId: session?.user?.id ?? null,
      guestEmail: !session?.user?.id ? contact.email : null,
      status: "pending",
      total,
      shippingName: contact.name,
      shippingAddress: shipping.address,
      shippingCity: shipping.city,
      shippingState: shipping.state,
      shippingZip: shipping.zip,
      shippingCountry: shipping.country,
      stripePaymentId: paymentIntent.id,
      items: {
        create: items.map(item => {
          const dbProduct = dbProducts.find(p => p.id === item.productId)!;
          return {
            productId: item.productId,
            quantity: item.quantity,
            unitPrice: Number(dbProduct.price),
          };
        }),
      },
    },
  });

  // Save shipping details to user profile if logged in
  if (session?.user?.id) {
    await db.user.update({
      where: { id: session.user.id },
      data: {
        shippingAddress: shipping.address,
        shippingCity: shipping.city,
        shippingState: shipping.state,
        shippingZip: shipping.zip,
        shippingCountry: shipping.country,
      },
    }).catch(() => {
      // Non-blocking - don't fail order if profile update fails
    });
  }

  return NextResponse.json({
    clientSecret: paymentIntent.client_secret,
    orderId: order.id,
    total,
  });
}

// Stripe webhook updates order status
export async function PATCH(req: NextRequest) {
  const { orderId, paymentIntentId } = await req.json() as { orderId: string; paymentIntentId: string };
  if (!orderId || !paymentIntentId) {
    return NextResponse.json({ error: "Missing fields." }, { status: 400 });
  }

  const stripe = await getStripeClient();
  const pi = await stripe.paymentIntents.retrieve(paymentIntentId);
  if (pi.status !== "succeeded") {
    return NextResponse.json({ error: "Payment not confirmed." }, { status: 400 });
  }

  await db.order.update({
    where: { id: orderId, stripePaymentId: paymentIntentId },
    data: { status: "paid" },
  });

  return NextResponse.json({ ok: true });
}
