import { NextRequest, NextResponse } from 'next/server'; import { auth } from '@/auth'; import { getUserInfo, getEffectiveTier } from '@/lib/entitlements'; import { stripe } from '@/lib/stripe'; import type Stripe from 'stripe'; import { priceIdToTier, getDynamicPrices, isBillingEnabled } from '@/lib/billing/stripe-prices'; export const dynamic = 'force-dynamic'; export async function GET(req: NextRequest) { const session = await auth(); if (!session?.user?.id) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } const userId = session.user.id; const { prisma } = await import('@/lib/prisma'); const sessionId = req.nextUrl.searchParams.get('session_id'); if (sessionId && sessionId.startsWith('cs_')) { try { const checkoutSession = await stripe.checkout.sessions.retrieve(sessionId); if (checkoutSession.subscription && checkoutSession.status === 'complete') { const subId = typeof checkoutSession.subscription === 'string' ? checkoutSession.subscription : (checkoutSession.subscription as any).id; const sub = await stripe.subscriptions.retrieve(subId) as any; const priceId = sub.items.data[0].price.id; const tier = (await priceIdToTier(priceId)) || (checkoutSession.metadata?.tier as any) || 'PRO'; const currentPeriodStartTimestamp = sub.current_period_start ?? sub.items?.data?.[0]?.current_period_start ?? sub.start_date ?? Math.floor(Date.now() / 1000); const currentPeriodEndTimestamp = sub.current_period_end ?? sub.items?.data?.[0]?.current_period_end ?? (currentPeriodStartTimestamp + 30 * 24 * 3600); await prisma.subscription.upsert({ where: { userId }, update: { tier, status: 'ACTIVE', stripeCustomerId: checkoutSession.customer as string, stripeSubscriptionId: sub.id, stripePriceId: priceId, currentPeriodStart: new Date(currentPeriodStartTimestamp * 1000), currentPeriodEnd: new Date(currentPeriodEndTimestamp * 1000), canceledAt: sub.canceled_at ? new Date(sub.canceled_at * 1000) : null, cancelAtPeriodEnd: sub.cancel_at_period_end, }, create: { userId, tier, status: 'ACTIVE', stripeCustomerId: checkoutSession.customer as string, stripeSubscriptionId: sub.id, stripePriceId: priceId, currentPeriodStart: new Date(currentPeriodStartTimestamp * 1000), currentPeriodEnd: new Date(currentPeriodEndTimestamp * 1000), }, }); } } catch (err) { console.error('[billing/status] Failed to sync Stripe session:', err); } } try { const { tier, status, currentPeriodEnd } = await getUserInfo(userId); const effectiveTier = await getEffectiveTier(userId); const subscription = await prisma.subscription.findUnique({ where: { userId } }); const prices = await getDynamicPrices(); const billingEnabled = await isBillingEnabled(); return NextResponse.json({ tier, effectiveTier, status, currentPeriodEnd: currentPeriodEnd ?? null, currentPeriodStart: subscription?.currentPeriodStart ?? null, cancelAtPeriodEnd: subscription?.cancelAtPeriodEnd ?? false, hasStripeSubscription: !!subscription?.stripeSubscriptionId, prices, billingEnabled, }); } catch (error) { console.error('[billing/status]', error); return NextResponse.json({ error: 'Failed to fetch billing status' }, { status: 500 }); } }