import { NextRequest, NextResponse } from "next/server";
import { headers } from "next/headers";
import { connectDB } from "@/lib/db";
import { getStripeForSecretKey } from "@/lib/stripe";
import { getSettings } from "@/models/settings.model";
import { resolveStripeCredentials } from "@/lib/credentials";
import {
  acquireWebhookLease,
  completeWebhookLease,
  failWebhookLease,
} from "@/lib/webhook-event-lease";
import {
  finalizeStripeCheckoutSessionOrder,
  finalizeStripePaymentIntentOrder,
} from "@/lib/stripe-orders";
import {
  processVendorCheckoutSessionCompleted,
  processVendorCheckoutSessionExpired,
  processVendorInvoicePaid,
  processVendorInvoicePaymentFailed,
  processVendorSubscriptionUpdated,
  VENDOR_APPLICATION_CHECKOUT_KIND,
} from "@/lib/vendor-stripe-billing";
import Stripe from "stripe";

/**
 * POST /api/payments/webhook
 * Stripe webhook handler
 */
export async function POST(request: NextRequest) {
  const body = await request.text();
  const headersList = await headers();
  const signature = headersList.get("stripe-signature");

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

  await connectDB();
  const settings = await getSettings();
  const stripeCreds = resolveStripeCredentials(settings.payment?.stripe);

  const webhookSecret = stripeCreds.webhookSecret;
  if (!webhookSecret) {
    console.error("Missing STRIPE_WEBHOOK_SECRET");
    return NextResponse.json(
      { error: "Webhook secret not configured" },
      { status: 500 },
    );
  }

  const stripeSecretKey = stripeCreds.secretKey;
  if (!stripeSecretKey) {
    console.error("Missing STRIPE_SECRET_KEY");
    return NextResponse.json(
      { error: "Stripe secret key not configured" },
      { status: 500 },
    );
  }

  const stripe = getStripeForSecretKey(stripeSecretKey);
  let event: Stripe.Event;

  try {
    event = stripe.webhooks.constructEvent(
      body,
      signature,
      webhookSecret,
    );
  } catch (err: unknown) {
    const message = err instanceof Error ? err.message : "Unknown error";
    console.error("Webhook signature verification failed:", message);
    return NextResponse.json({ error: "Invalid signature" }, { status: 400 });
  }

  const acquired = await acquireWebhookLease(event);
  if (!acquired) {
    return NextResponse.json({ received: true, duplicate: true });
  }

  try {
    switch (event.type) {
      case "checkout.session.completed": {
        const session = event.data.object as Stripe.Checkout.Session;
        const handled = await processVendorCheckoutSessionCompleted(
          session,
          stripe,
        );
        if (!handled) await finalizeStripeCheckoutSessionOrder(session, settings);
        break;
      }

      case "checkout.session.expired": {
        const session = event.data.object as Stripe.Checkout.Session;
        const handled = await processVendorCheckoutSessionExpired(session);
        if (!handled) console.log("Checkout session expired:", session.id);
        break;
      }

      case "customer.subscription.created":
      case "customer.subscription.updated":
      case "customer.subscription.deleted": {
        const subscription = event.data.object as Stripe.Subscription;
        await processVendorSubscriptionUpdated(subscription, settings, stripe);
        break;
      }

      case "invoice.paid": {
        const invoice = event.data.object as Stripe.Invoice;
        const handled = await processVendorInvoicePaid(invoice, settings, stripe);
        if (!handled) console.log("Invoice paid:", invoice.id);
        break;
      }

      case "invoice.payment_failed":
      case "invoice.payment_action_required": {
        const invoice = event.data.object as Stripe.Invoice;
        const handled = await processVendorInvoicePaymentFailed(
          invoice,
          settings,
          stripe,
        );
        if (!handled) console.log("Invoice payment failed:", invoice.id);
        break;
      }

      case "payment_intent.succeeded": {
        const paymentIntent = event.data.object as Stripe.PaymentIntent;
        const rawIntent = paymentIntent as unknown as { invoice?: unknown };
        if (
          paymentIntent.metadata?.kind !== VENDOR_APPLICATION_CHECKOUT_KIND &&
          !rawIntent.invoice
        ) {
          await finalizeStripePaymentIntentOrder(paymentIntent, settings);
        }
        break;
      }

      case "payment_intent.payment_failed": {
        const paymentIntent = event.data.object as Stripe.PaymentIntent;
        if (paymentIntent.metadata?.kind !== VENDOR_APPLICATION_CHECKOUT_KIND) {
          console.log("Payment failed:", paymentIntent.id);
        }
        break;
      }

      default:
        console.log(`Unhandled event type: ${event.type}`);
    }

    await completeWebhookLease(event.id);
  } catch (error) {
    await failWebhookLease(event.id, error);
    throw error;
  }

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