import { NextRequest, NextResponse } from "next/server";
import Stripe from "stripe";
import { getCurrentUser } from "@/lib/auth/session";
import { buildCheckoutParams } from "@/lib/billing/checkout";
import { MAX_JSON_BODY_BYTES } from "@/lib/limits";
import { readJsonSized } from "@/lib/http/requestSize";
import { requireCsrf } from "@/lib/auth/csrf";
import { originForFirstPartyHost } from "@/lib/seo/site";

const stripe = process.env.STRIPE_SECRET_KEY
  ? new Stripe(process.env.STRIPE_SECRET_KEY, {
      apiVersion: "2025-01-27.acacia" as any,
      // Transient connection blips (e.g. right after a container restart, before
      // the network is fully settled) otherwise surface straight to the user as
      // a failed checkout. Stripe's SDK retries are safe here: session creation
      // carries an auto-generated idempotency key, so a retry after a dropped
      // connection can't double-create a session.
      maxNetworkRetries: 2,
    })
  : null;

export const runtime = "nodejs";

/**
 * Base origin for the Stripe success/cancel URLs.
 *
 * The checkout is initiated same-origin from the app (main host or app.*
 * subdomain). Returning to exactly that host keeps the user inside the origin
 * they started the purchase on (mirroring the Google sign-in return flow);
 * the host is validated against the first-party allowlist (see
 * originForFirstPartyHost), falling back to the main domain for any
 * non-first-party Host.
 */
function checkoutBaseUrl(req: NextRequest): string {
  return originForFirstPartyHost(req.headers.get("host") || "");
}

export async function POST(req: NextRequest) {
  try {
    const csrfBlocked = requireCsrf(req);
    if (csrfBlocked) return csrfBlocked;

    const user = await getCurrentUser(req);
    if (!user) {
      return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
    }

    const parsed = await readJsonSized<{ plan?: string; email?: string }>(
      req,
      MAX_JSON_BODY_BYTES
    );
    if (!parsed.ok) return parsed.response;
    const body = parsed.body ?? {};
    const { plan, email } = body;
    const appUrl = checkoutBaseUrl(req);

    // Prices, trials, intervals and mode are decided server-side by the pure
    // builder against the shared catalog in src/lib/billing/pricing.ts — the
    // request body only ever supplies the plan identifier.
    const params = buildCheckoutParams(user, plan, process.env);

    // Mock simulation mode when Stripe is not configured with a real Secret Key
    if (!stripe) {
      return NextResponse.json({
        url: `${appUrl}/dashboard?checkout_success=true&plan=${params.metadata.plan}`,
        mock: true,
      });
    }

    const session = await stripe.checkout.sessions.create({
      payment_method_types: ["card"],
      line_items: params.lineItems,
      mode: params.mode,
      customer_email: email || undefined,
      client_reference_id: params.clientReferenceId,
      // Must land on /dashboard, not the bare root: middleware.ts unconditionally
      // redirects "/" to the locale-prefixed marketing page and drops the query
      // string, which would silently strand a paying customer on the landing
      // page instead of back in the app.
      success_url: `${appUrl}/dashboard?checkout_success=true&session_id={CHECKOUT_SESSION_ID}&plan=${params.metadata.plan}`,
      cancel_url: `${appUrl}/dashboard?checkout_canceled=true`,
      subscription_data: params.subscriptionData,
      metadata: params.metadata,
    });

    return NextResponse.json({ url: session.url, sessionId: session.id });
  } catch (error: any) {
    console.error("Stripe Checkout Error:", error);
    return NextResponse.json(
      { error: error?.message || "Fehler beim Erstellen der Checkout-Session" },
      { status: 500 }
    );
  }
}
