import { NextResponse } from 'next/server';
import { withErrorHandler } from '@server/middleware/withErrorHandler';
import { withAuth, AuthedRequest } from '@server/middleware/withAuth';
import { getStripeClientFromDb } from '@server/lib/stripe';
import { db, plans, subscriptions, restaurants } from '@server/db/drizzle';
import { eq, and, sql } from 'drizzle-orm';
import { initDatabase } from '@server/db/init';

export const POST = withErrorHandler(
  withAuth(async (req: AuthedRequest) => {
    await initDatabase();
    const { planId, billingCycle } = await req.json();
    if (!planId) {
      return NextResponse.json({ error: 'planId is required', code: 'VALIDATION_ERROR' }, { status: 400 });
    }

    const stripe = await getStripeClientFromDb();
    const restaurantId = req.session.restaurantId!;

    const planRows = await db.select({
      id: plans.id,
      name: plans.name,
      price_monthly: plans.priceMonthly,
      price_annual: plans.priceAnnual,
      stripe_price_id_monthly: plans.stripePriceIdMonthly,
      stripe_price_id_annual: plans.stripePriceIdAnnual,
    })
    .from(plans)
    .where(and(eq(plans.id, planId), eq(plans.isActive, true)));
    const plan = planRows[0];

    if (!plan) {
      return NextResponse.json({ error: 'Plan not found', code: 'NOT_FOUND' }, { status: 404 });
    }

    const priceId = billingCycle === 'annual' ? plan.stripe_price_id_annual : plan.stripe_price_id_monthly;
    if (!priceId) {
      return NextResponse.json(
        { error: 'Stripe price ID not configured for this plan. Please contact support.', code: 'STRIPE_NOT_CONFIGURED' },
        { status: 503 }
      );
    }

    const subRows = await db.select({
      stripeCustomerId: subscriptions.stripeCustomerId,
      stripeSubscriptionId: subscriptions.stripeSubscriptionId,
    })
    .from(subscriptions)
    .where(eq(subscriptions.restaurantId, restaurantId))
    .limit(1);
    const sub = subRows[0];

    const restRows = await db.select({ name: restaurants.name })
      .from(restaurants)
      .where(eq(restaurants.id, restaurantId));
    const restaurant = restRows[0];

    const userEmail = req.session.email;

    let customerId = sub?.stripeCustomerId ?? null;
    if (!customerId) {
      const customer = await stripe.customers.create({
        email: userEmail ?? undefined,
        name: restaurant?.name ?? undefined,
        metadata: { restaurant_id: restaurantId },
      });
      customerId = customer.id;

      await db.insert(subscriptions)
        .values({ restaurantId, stripeCustomerId: customerId })
        .onConflictDoUpdate({
          target: subscriptions.restaurantId,
          set: { stripeCustomerId: customerId },
        });
    }

    const rawHost = req.headers.get('host');
    const origin =
      process.env.NEXT_PUBLIC_APP_URL ??
      (process.env.VERCEL_URL ? `https://${process.env.VERCEL_URL}` : null) ??
      req.headers.get('origin') ??
      (rawHost ? `https://${rawHost}` : null);

    const existingStripeSubId = sub?.stripeSubscriptionId ?? null;
    if (existingStripeSubId) {
      try {
        const stripeSub = await stripe.subscriptions.retrieve(existingStripeSubId);
        if (stripeSub.status === 'active' || stripeSub.status === 'trialing') {
          const itemId = stripeSub.items.data[0]?.id;
          if (itemId) {
            await stripe.subscriptions.update(existingStripeSubId, {
              items: [{ id: itemId, price: priceId }],
              proration_behavior: 'always_invoice',
              metadata: { restaurant_id: restaurantId, plan_id: planId },
            });
            await db.update(subscriptions)
              .set({ planId, stripePriceId: priceId })
              .where(eq(subscriptions.restaurantId, restaurantId));
            return NextResponse.json({ redirect: `${origin}/billing?checkout=success` });
          }
        }
      } catch (err) {
        console.warn('[Billing] Could not update existing subscription, falling through to Checkout:', err instanceof Error ? err.message : err);
      }
    }

    const session = await stripe.checkout.sessions.create({
      customer: customerId,
      mode: 'subscription',
      line_items: [{ price: priceId, quantity: 1 }],
      success_url: `${origin}/billing?checkout=success&session_id={CHECKOUT_SESSION_ID}`,
      cancel_url: `${origin}/billing?checkout=cancelled`,
      metadata: { restaurant_id: restaurantId, plan_id: planId },
      subscription_data: {
        metadata: { restaurant_id: restaurantId, plan_id: planId },
      },
    });

    return NextResponse.json({ url: session.url });
  })
);
