import { NextRequest, NextResponse } from "next/server";
import { auth } from "@/lib/auth";
import { db } from "@/lib/db";
import {
  organizations,
  organizationMembers,
  promoCodes,
} from "@memctl/db/schema";
import { eq, and, count } from "drizzle-orm";
import { headers } from "next/headers";
import { createCheckoutSession, STRIPE_PLANS } from "@/lib/stripe";
import { isBillingEnabled } from "@/lib/plans";
import { PLANS, type PlanId } from "@memctl/shared/constants";

export async function POST(
  req: NextRequest,
  { params }: { params: Promise<{ slug: string }> },
) {
  if (!isBillingEnabled()) {
    return NextResponse.json(
      { error: "Billing is not enabled" },
      { status: 400 },
    );
  }

  const session = await auth.api.getSession({
    headers: await headers(),
  });
  if (!session) {
    return NextResponse.json({ error: "Not authenticated" }, { status: 401 });
  }

  const { slug } = await params;

  const [org] = await db
    .select()
    .from(organizations)
    .where(eq(organizations.slug, slug))
    .limit(1);

  if (!org) {
    return NextResponse.json(
      { error: "Organization not found" },
      { status: 404 },
    );
  }

  // Verify owner or admin
  const [member] = await db
    .select()
    .from(organizationMembers)
    .where(
      and(
        eq(organizationMembers.orgId, org.id),
        eq(organizationMembers.userId, session.user.id),
      ),
    )
    .limit(1);

  if (!member || member.role === "member") {
    return NextResponse.json(
      { error: "Insufficient permissions" },
      { status: 403 },
    );
  }

  const body = await req.json().catch(() => null);
  const planId = body?.planId;
  const promoCode = body?.promoCode;

  if (!planId || !STRIPE_PLANS[planId]) {
    return NextResponse.json({ error: "Invalid plan" }, { status: 400 });
  }

  // Prevent duplicate subscriptions: check Stripe directly in case the webhook
  // hasn't updated the DB yet.
  if (org.stripeSubscriptionId) {
    return NextResponse.json(
      { error: "Organization already has an active subscription. Use the billing portal to switch plans." },
      { status: 400 },
    );
  }
  if (org.stripeCustomerId) {
    const { getStripe } = await import("@/lib/stripe");
    const existing = await getStripe().subscriptions.list({
      customer: org.stripeCustomerId,
      status: "active",
      limit: 1,
    });
    if (existing.data.length > 0) {
      // Sync the subscription ID the webhook missed
      await db
        .update(organizations)
        .set({ stripeSubscriptionId: existing.data[0].id })
        .where(eq(organizations.id, org.id));
      return NextResponse.json(
        { error: "Organization already has an active subscription. Use the billing portal to switch plans." },
        { status: 400 },
      );
    }
  }

  let customerId = org.stripeCustomerId;
  if (!customerId) {
    try {
      const { getStripe } = await import("@/lib/stripe");
      const customer = await getStripe().customers.create({
        email: session.user.email,
        name: org.name,
        metadata: { orgSlug: slug, orgId: org.id },
      });
      customerId = customer.id;
      await db
        .update(organizations)
        .set({ stripeCustomerId: customerId })
        .where(eq(organizations.id, org.id));
    } catch {
      return NextResponse.json(
        { error: "Failed to create billing customer" },
        { status: 500 },
      );
    }
  }

  // Resolve promo code to Stripe promotion code ID
  let stripePromoCodeId: string | undefined;
  if (promoCode) {
    const [promo] = await db
      .select()
      .from(promoCodes)
      .where(
        and(
          eq(promoCodes.code, promoCode.toUpperCase()),
          eq(promoCodes.active, true),
        ),
      )
      .limit(1);
    if (promo) {
      stripePromoCodeId = promo.stripePromoCodeId;
    }
  }

  const appUrl = process.env.NEXT_PUBLIC_APP_URL ?? "http://localhost:3000";
  const [memberCount] = await db
    .select({ value: count() })
    .from(organizationMembers)
    .where(eq(organizationMembers.orgId, org.id));

  const selectedPlan = PLANS[planId as PlanId];
  const includedSeats =
    selectedPlan && selectedPlan.memberLimit !== Infinity
      ? selectedPlan.memberLimit
      : 0;
  const extraSeatQuantity = Math.max(
    0,
    (memberCount?.value ?? 0) - includedSeats,
  );

  const checkoutSession = await createCheckoutSession({
    customerId,
    priceId: STRIPE_PLANS[planId].priceId,
    planId: planId as PlanId,
    orgSlug: slug,
    successUrl: `${appUrl}/org/${slug}/billing?success=true`,
    cancelUrl: `${appUrl}/org/${slug}/billing?canceled=true`,
    stripePromoCodeId,
    extraSeatQuantity,
  });

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