import { NextResponse } from "next/server";
import type Stripe from "stripe";
import { prisma } from "@/lib/prisma";
import { getStripe, TIER_CONFIG } from "@/lib/stripe";

export const runtime = "nodejs";

function tierFromPriceId(priceId: string | null): "FREE" | "STARTER" | "PRO" {
  if (priceId === TIER_CONFIG.STARTER.priceId) return "STARTER";
  if (priceId === TIER_CONFIG.PRO.priceId) return "PRO";
  return "FREE";
}

function sessionsLimitForTier(tier: "FREE" | "STARTER" | "PRO"): number {
  return TIER_CONFIG[tier].sessionsLimit;
}

async function handleCheckoutCompleted(
  checkoutSession: Stripe.Checkout.Session
) {
  const userId = checkoutSession.metadata?.userId;
  if (!userId) return;

  const subscriptionId = checkoutSession.subscription as string;
  const customerId = checkoutSession.customer as string;

  const sub = await getStripe().subscriptions.retrieve(subscriptionId);
  const firstItem = sub.items.data[0];
  const priceId = firstItem?.price?.id ?? null;
  const tier = tierFromPriceId(priceId);
  const periodStart = firstItem?.current_period_start
    ? new Date(firstItem.current_period_start * 1000)
    : new Date();
  const periodEnd = firstItem?.current_period_end
    ? new Date(firstItem.current_period_end * 1000)
    : new Date();

  await prisma.subscription.upsert({
    where: { userId },
    update: {
      stripeCustomerId: customerId,
      stripeSubscriptionId: subscriptionId,
      stripePriceId: priceId,
      tier,
      sessionsLimit: sessionsLimitForTier(tier),
      sessionsUsed: 0,
      status: "ACTIVE",
      currentPeriodStart: periodStart,
      currentPeriodEnd: periodEnd,
    },
    create: {
      userId,
      stripeCustomerId: customerId,
      stripeSubscriptionId: subscriptionId,
      stripePriceId: priceId,
      tier,
      sessionsLimit: sessionsLimitForTier(tier),
      sessionsUsed: 0,
      status: "ACTIVE",
      currentPeriodStart: periodStart,
      currentPeriodEnd: periodEnd,
    },
  });
}

async function handleSubscriptionUpdated(sub: Stripe.Subscription) {
  const firstItem = sub.items.data[0];
  const priceId = firstItem?.price?.id ?? null;
  const tier = tierFromPriceId(priceId);

  const statusMap: Record<string, "ACTIVE" | "PAST_DUE" | "CANCELED" | "UNPAID"> = {
    active: "ACTIVE",
    past_due: "PAST_DUE",
    canceled: "CANCELED",
    unpaid: "UNPAID",
  };

  const dbStatus = statusMap[sub.status] ?? "ACTIVE";
  const periodStart = firstItem?.current_period_start
    ? new Date(firstItem.current_period_start * 1000)
    : undefined;
  const periodEnd = firstItem?.current_period_end
    ? new Date(firstItem.current_period_end * 1000)
    : undefined;

  await prisma.subscription.updateMany({
    where: { stripeSubscriptionId: sub.id },
    data: {
      tier,
      stripePriceId: priceId,
      sessionsLimit: sessionsLimitForTier(tier),
      status: dbStatus,
      ...(periodStart && { currentPeriodStart: periodStart }),
      ...(periodEnd && { currentPeriodEnd: periodEnd }),
    },
  });
}

async function handleSubscriptionDeleted(sub: Stripe.Subscription) {
  await prisma.subscription.updateMany({
    where: { stripeSubscriptionId: sub.id },
    data: {
      status: "CANCELED",
      tier: "FREE",
      sessionsLimit: TIER_CONFIG.FREE.sessionsLimit,
    },
  });
}

async function handleInvoicePaid(invoice: Stripe.Invoice) {
  const subDetail = invoice.parent?.subscription_details?.subscription;
  const subscriptionId =
    typeof subDetail === "string" ? subDetail : subDetail?.id;

  if (!subscriptionId) return;

  await prisma.subscription.updateMany({
    where: { stripeSubscriptionId: subscriptionId },
    data: { sessionsUsed: 0 },
  });
}

export async function POST(request: Request) {
  const body = await request.text();
  const sig = request.headers.get("stripe-signature");

  if (!sig) {
    return NextResponse.json(
      { error: "Missing stripe-signature header" },
      { status: 400 }
    );
  }

  let event: Stripe.Event;
  try {
    event = getStripe().webhooks.constructEvent(
      body,
      sig,
      process.env.STRIPE_WEBHOOK_SECRET!
    );
  } catch (err) {
    console.error("Webhook signature verification failed");
    return NextResponse.json(
      { error: "Invalid signature" },
      { status: 400 }
    );
  }

  try {
    switch (event.type) {
      case "checkout.session.completed":
        await handleCheckoutCompleted(
          event.data.object as Stripe.Checkout.Session
        );
        break;
      case "customer.subscription.updated":
        await handleSubscriptionUpdated(
          event.data.object as Stripe.Subscription
        );
        break;
      case "customer.subscription.deleted":
        await handleSubscriptionDeleted(
          event.data.object as Stripe.Subscription
        );
        break;
      case "invoice.paid":
        await handleInvoicePaid(event.data.object as Stripe.Invoice);
        break;
    }
  } catch (error) {
    console.error(`Error handling ${event.type}:`, error);
    return NextResponse.json(
      { error: "Webhook handler failed" },
      { status: 500 }
    );
  }

  return NextResponse.json({ received: true }, { status: 200 });
}
