import { NextRequest, NextResponse } from "next/server";
import {
  CREDIT_PRICE_CENTS,
  FREE_EXTRA_CREDITS_MAX,
  FREE_TOP_UP_MAX,
  FREE_TOP_UP_MIN,
  formatCreditPrice,
  validateFreeTopUpAmount,
} from "@/lib/credits";
import { prisma } from "@/lib/db";
import { getSessionUser } from "@/lib/session";
import {
  checkoutTaxAndReferenceOptions,
  ensureStripeCustomer,
  priceDataTaxFields,
  productDataWithTaxCode,
} from "@/lib/stripe-checkout";
import { getStripe, isBillingDevMock, isStripeConfigured } from "@/lib/stripe";
import { grantExtraCredits } from "@/lib/billing";

export async function GET() {
  const user = await getSessionUser();
  if (!user) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  const dbUser = await prisma.user.findUniqueOrThrow({
    where: { id: user.id },
    select: {
      extraCredits: true,
      plan: true,
      monthlyCredits: true,
      videosUsed: true,
    },
  });

  const purchases = await prisma.creditPurchase.findMany({
    where: { userId: user.id, status: "COMPLETED" },
    orderBy: { completedAt: "desc" },
    take: 10,
  });

  const cap = FREE_EXTRA_CREDITS_MAX;
  const room = Math.max(0, cap - dbUser.extraCredits);

  return NextResponse.json({
    extraCredits: dbUser.extraCredits,
    videoCredits: dbUser.extraCredits,
    topUpMin: FREE_TOP_UP_MIN,
    topUpMax: FREE_TOP_UP_MAX,
    priceCentsPerCredit: CREDIT_PRICE_CENTS,
    priceLabelPerCredit: formatCreditPrice(1),
    creditBalanceMax: cap,
    monthlyCredits: dbUser.monthlyCredits,
    creditsUsed: dbUser.videosUsed,
    plan: dbUser.plan,
    stripeConfigured: isStripeConfigured() || isBillingDevMock(),
    room,
    atExtraCap: room === 0,
    purchases: purchases.map((p) => ({
      id: p.id,
      credits: p.credits,
      amountCents: p.amountCents,
      completedAt: p.completedAt?.toISOString() ?? null,
    })),
  });
}

/** Free tier: top up 1–15 extra credits (price = credits × €0.25). */
export async function POST(req: NextRequest) {
  const user = await getSessionUser();
  if (!user) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  if (user.plan === "PREMIUM") {
    return NextResponse.json(
      {
        error:
          "Credit top-ups are for the Free plan. Pro includes 50 monthly credits; existing extras never expire.",
      },
      { status: 403 },
    );
  }

  let credits = 0;
  try {
    const body = await req.json();
    credits = Math.floor(Number(body.credits));
  } catch {
    return NextResponse.json({ error: "Invalid request body" }, { status: 400 });
  }

  const dbUser = await prisma.user.findUniqueOrThrow({
    where: { id: user.id },
    select: { extraCredits: true, email: true, monthlyCredits: true, videosUsed: true, bonusQuota: true },
  });

  const monthlyRemaining = Math.max(
    0,
    dbUser.monthlyCredits + dbUser.bonusQuota - dbUser.videosUsed,
  );
  const validation = validateFreeTopUpAmount(credits, dbUser.extraCredits, monthlyRemaining);
  if (!validation.ok) {
    return NextResponse.json({ error: validation.error }, { status: 400 });
  }

  const { credits: amount, amountCents } = validation;

  if (isBillingDevMock()) {
    const purchase = await prisma.creditPurchase.create({
      data: {
        userId: user.id,
        credits: amount,
        amountCents,
        status: "COMPLETED",
        completedAt: new Date(),
        stripeSessionId: `dev_topup_${Date.now()}`,
      },
    });
    await grantExtraCredits(user.id, amount);
    return NextResponse.json({
      mocked: true,
      granted: amount,
      amountCents,
      purchaseId: purchase.id,
    });
  }

  if (!isStripeConfigured()) {
    return NextResponse.json(
      { error: "Payments are not configured yet. Set STRIPE_SECRET_KEY." },
      { status: 503 },
    );
  }

  const origin = process.env.NEXTAUTH_URL || req.nextUrl.origin;
  const purchase = await prisma.creditPurchase.create({
    data: {
      userId: user.id,
      credits: amount,
      amountCents,
      status: "PENDING",
    },
  });

  try {
    const stripe = getStripe();
    const customerId = await ensureStripeCustomer(user.id, dbUser.email);
    const session = await stripe.checkout.sessions.create({
      mode: "payment",
      customer: customerId,
      line_items: [
        {
          quantity: amount,
          price_data: {
            currency: "eur",
            unit_amount: CREDIT_PRICE_CENTS,
            ...priceDataTaxFields(),
            product_data: productDataWithTaxCode(
              "Songs2VID video credit",
              `1 credit = 1 video upload (${formatCreditPrice(1)} each)`,
            ),
          },
        },
      ],
      metadata: {
        type: "free_top_up",
        userId: user.id,
        purchaseId: purchase.id,
        credits: String(amount),
      },
      ...checkoutTaxAndReferenceOptions(user.id),
      success_url: `${origin}/dashboard/settings?credits=success`,
      cancel_url: `${origin}/dashboard/settings?credits=cancelled`,
    });

    await prisma.creditPurchase.update({
      where: { id: purchase.id },
      data: { stripeSessionId: session.id },
    });

    return NextResponse.json({ url: session.url, sessionId: session.id });
  } catch (err) {
    await prisma.creditPurchase.update({
      where: { id: purchase.id },
      data: { status: "FAILED" },
    });
    const message = err instanceof Error ? err.message : "Checkout failed";
    return NextResponse.json({ error: message }, { status: 500 });
  }
}
