import { NextRequest, NextResponse } from "next/server";
import Stripe from "stripe";
import { stripe } from "@/lib/stripe";
import { logger } from "@/lib/logger";
import { syncStripeSubscriptionToConvex } from "@/lib/payments/sync-stripe-subscription";
import { convexQuery, convexMutation } from "@/lib/convex-client";

const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET!;

if (!webhookSecret) {
  logger.error("STRIPE_WEBHOOK_SECRET is not configured");
}

/**
 * Helper to extract a subscription ID from a Stripe Invoice.
 * In Stripe SDK v20+, `invoice.subscription` was removed;
 * the subscription lives at `invoice.parent.subscription_details.subscription`.
 */
function getSubscriptionIdFromInvoice(invoice: Stripe.Invoice): string {
  const sub = invoice.parent?.subscription_details?.subscription;
  if (typeof sub === "string") return sub;
  if (sub && typeof sub === "object" && "id" in sub) return sub.id;
  return "";
}

/**
 * Helper to check if an invoice line item is a proration.
 * In Stripe SDK v20+, `line.proration` was moved to
 * `line.parent.invoice_item_details.proration`.
 */
function isProrationLine(line: Stripe.InvoiceLineItem): boolean {
  return line.parent?.invoice_item_details?.proration === true;
}

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

    if (!sig) {
      logger.error("No signature provided in webhook request");
      return NextResponse.json(
        { error: "No signature provided" },
        { status: 400 },
      );
    }

    // Verify webhook signature
    let event: Stripe.Event;
    try {
      event = stripe.webhooks.constructEvent(body, sig, webhookSecret);
    } catch (err) {
      logger.error("Webhook signature verification failed", {
        error: err instanceof Error ? err.message : String(err),
      });
      return NextResponse.json({ error: "Invalid signature" }, { status: 400 });
    }

    // Handle the event
    logger.info(`Received event: ${event.type}`, { eventId: event.id });

    switch (event.type) {
      case "checkout.session.completed": {
        const session = event.data.object as Stripe.Checkout.Session;
        logger.info("Checkout session completed", { sessionId: session.id });

        try {
          const customerId = session.customer as string;
          const subscriptionId = session.subscription as string;
          const customerEmail = session.customer_details?.email || "";
          const requiresOTP = session.metadata?.requires_otp === "true";
          const userId = session.metadata?.user_id;
          const setupFeeAmount = session.metadata?.setup_fee_amount
            ? parseInt(session.metadata.setup_fee_amount)
            : null;

          // ── Handle booking deposit payment (WhatsApp bookings) ──────
          if (session.metadata?.type === "booking_deposit") {
            const bookingId = session.metadata?.booking_id;
            const customerPhone = session.metadata?.customer_phone;
            const orgId = session.metadata?.organization_id;
            const serviceName = session.metadata?.service;
            const appointmentDate = session.metadata?.appointment_date;
            const appointmentTime = session.metadata?.appointment_time;

            if (bookingId) {
              try {
                // Update booking: confirmed + depositPaid
                await convexMutation("bookings/mutations:updateDepositInfo", {
                  id: bookingId,
                  depositPaymentId: session.payment_intent as string || session.id,
                  depositAmount: session.amount_total ? session.amount_total / 100 : undefined,
                  status: "confirmed",
                });

                logger.info("Booking deposit paid — status confirmed", {
                  bookingId,
                  sessionId: session.id,
                  customerPhone,
                });

                // Send WhatsApp confirmation message
                if (customerPhone && orgId) {
                  try {
                    const { twilioWhatsAppService } = await import("@/lib/services/twilio-whatsapp.service");
                    const { convexQuery: cq } = await import("@/lib/convex-client");

                    // Get org credentials
                    const credentials = await twilioWhatsAppService.getCredentialsForOrg(orgId);
                    if (credentials) {
                      // Get company display name
                      const orgData = await cq<{ ownerId?: string; name?: string } | null>(
                        "organizations/queries:getOrganization",
                        { id: orgId },
                      );
                      let companyName = orgData?.name || "the clinic";
                      if (orgData?.ownerId) {
                        const owner = await cq<{ companyName?: string } | null>(
                          "auth/queries:getUser",
                          { id: orgData.ownerId },
                        );
                        if (owner?.companyName) companyName = owner.companyName;
                      }

                      const dateStr = appointmentDate
                        ? new Date(appointmentDate).toLocaleDateString("en-GB", { weekday: "long", day: "numeric", month: "long", year: "numeric" })
                        : "";

                      const confirmMsg = `✅ Your deposit payment has been received!\n\nYour ${serviceName || "Consultation"} is now *CONFIRMED*:\n📅 ${dateStr}\n🕐 ${appointmentTime || ""}\n\nThank you for choosing ${companyName}! We look forward to seeing you.`;

                      await twilioWhatsAppService.sendTextMessage(
                        credentials,
                        `whatsapp:${customerPhone}`,
                        confirmMsg,
                      );

                      logger.info("Booking confirmation WhatsApp sent", { customerPhone, bookingId });
                    }
                  } catch (waErr) {
                    logger.warn("Failed to send WhatsApp booking confirmation", { error: waErr, bookingId });
                  }
                }
              } catch (err) {
                logger.error("Failed to confirm booking deposit", { bookingId, error: err });
              }
            }
            break;
          }

          // Handle quotation payment
          if (session.metadata?.type === "quotation_payment") {
            const quotationId = session.metadata?.quotationId;

            if (quotationId && session.amount_total) {
              const amountPaid = session.amount_total / 100;
              const currency = (session.currency || "qar").toUpperCase();
              const paymentIntentId =
                (session.payment_intent as string) || session.id;

              try {
                await convexMutation(
                  "quotations/mutations:recordPayment",
                  {
                    quotationId,
                    amount: amountPaid,
                    currency,
                    method: "STRIPE",
                    stripePaymentIntentId: paymentIntentId,
                  },
                );

                logger.info("Quotation payment recorded via Convex", {
                  quotationId,
                  amountPaid,
                  paymentIntentId,
                  sessionId: session.id,
                });
              } catch (convexErr) {
                logger.error("Failed to record quotation payment in Convex", {
                  quotationId,
                  error: convexErr instanceof Error ? convexErr.message : String(convexErr),
                });
              }
            } else {
              logger.warn("Invalid quotation_payment metadata", {
                sessionId: session.id,
                metadata: session.metadata,
              });
            }
            break;
          }

          // Handle seat purchase (one-time payment)
          if (session.metadata?.type === "seat_purchase") {
            const orgId = session.metadata?.organizationId;
            const seatQuantity = parseInt(session.metadata?.quantity || "0");

            if (orgId && seatQuantity > 0) {
              logger.info("Processing seat purchase", {
                organizationId: orgId,
                quantity: seatQuantity,
                sessionId: session.id,
              });

              await convexMutation("organizations/mutations:addSeats", {
                organizationId: orgId,
                quantity: seatQuantity,
              });

              logger.info("Seat purchase completed via Convex", {
                organizationId: orgId,
                seatQuantity,
                amount: session.amount_total,
              });
            }
            break;
          }

          if (subscriptionId) {
            // IDEMPOTENCY CHECK: See if subscription already exists in Convex
            const existingSubscription = await convexQuery<Record<string, unknown>>(
              "billing/queries:getByStripeSubscriptionId",
              { stripeSubscriptionId: subscriptionId },
            );

            if (existingSubscription) {
              logger.info("Subscription already exists (idempotent)", {
                subscriptionId,
                existingId: existingSubscription._id,
                webhookEventId: event.id,
              });
              break;
            }

            // Find user by user_id or email in Convex
            let user: Record<string, unknown> | null = null;
            if (userId) {
              user = await convexQuery<Record<string, unknown>>(
                "auth/queries:getUserByEmail",
                { email: userId },
              );
              // userId might be an actual ID, not email — try direct lookup
              if (!user) {
                // The getUserByEmail won't work for IDs, but updateUserNoAuth uses userId string
                // We'll find the user by email below
              }
            }
            if (!user && customerEmail) {
              user = await convexQuery<Record<string, unknown>>(
                "auth/queries:getUserByEmail",
                { email: customerEmail },
              );
            }

            if (user) {
              const userIdStr = (user._id || user.id || userId) as string;

              // Get subscription details from Stripe (expand payment method)
              const stripeSubscription = await stripe.subscriptions.retrieve(
                subscriptionId,
                { expand: ["default_payment_method"] },
              );

              // Extract payment method details
              let paymentMethodId: string | null = null;
              let cardBrand: string | null = null;
              let cardLastFour: string | null = null;

              if (stripeSubscription.default_payment_method) {
                const pm =
                  stripeSubscription.default_payment_method as Stripe.PaymentMethod;
                paymentMethodId = pm.id;
                if (pm.card) {
                  cardBrand = pm.card.brand;
                  cardLastFour = pm.card.last4;
                }
              }

              // Always use Stripe's real subscription status.
              // "pending_verification" is a legacy concept — Stripe already determines
              // whether a subscription is active or trialing.
              const stripeStatus = stripeSubscription.status;
              const initialStatus =
                stripeStatus === "active" || stripeStatus === "trialing"
                  ? stripeStatus
                  : "active";
              if (requiresOTP) {
                logger.info("OTP required for this checkout but using Stripe status", {
                  stripeStatus,
                  userId: userIdStr,
                });
              }

              // Get current period end — use subscription item's current_period_end first.
              // Never use trial_end as the period end: if the trial already ended,
              // trial_end is in the past and would mark the subscription as expired immediately.
              const nowSec = Math.floor(Date.now() / 1000);
              const itemPeriodEnd = stripeSubscription.items?.data?.[0]?.current_period_end;
              const trialEnd = stripeSubscription.trial_end;
              const periodEndTimestamp =
                itemPeriodEnd ||
                (trialEnd && trialEnd > nowSec ? trialEnd : null) ||
                nowSec + 30 * 24 * 60 * 60; // fallback: 30 days
              const currentPeriodEnd = new Date(
                (periodEndTimestamp as number) * 1000,
              );
              const firstItem = stripeSubscription.items?.data?.[0];

              // Create subscription in Convex
              const convexSubId = await convexMutation(
                "billing/mutations:createSubscription",
                {
                  userId: userIdStr,
                  stripeCustomerId: customerId,
                  stripeSubscriptionId: subscriptionId,
                  stripePriceId: firstItem?.price?.id || "",
                  tierId: session.metadata?.tier_id || "",
                  status: initialStatus,
                  billingPeriod: session.metadata?.billing_period || "monthly",
                  currentPeriodEnd: currentPeriodEnd.getTime(),
                  // Only store trialEndsAt if subscription is actually in trial
                  trialEndsAt:
                    initialStatus === "trialing" && trialEnd
                      ? trialEnd * 1000
                      : undefined,
                },
              );

              logger.info("Subscription created in Convex from webhook", {
                convexSubId,
                userId: userIdStr,
                stripeSubscriptionId: subscriptionId,
              });

              // Update user with Stripe customer ID and package info
              await convexMutation("auth/mutations:updateUserNoAuth", {
                userId: userIdStr,
                stripeCustomerId: customerId,
                selectedPackage:
                  session.metadata?.tier_id || (user.selectedPackage as string) || undefined,
                preferredCurrency: (
                  session.metadata?.currency ||
                  session.currency ||
                  "QAR"
                ).toUpperCase(),
                selectedBillingPeriod:
                  (session.metadata?.billing_period as
                    | "monthly"
                    | "yearly"
                    | undefined) || "monthly",
                isTrialOver: true,
                ...(session.metadata?.has_setup_fee === "true"
                  ? { setupFeePaid: true, setupFeePaidAt: Date.now() }
                  : {}),
              });

              // Sync to Convex subscription table (dual-write for compatibility)
              await syncStripeSubscriptionToConvex({
                prismaSubscriptionId: (convexSubId as string) || "",
                userId: userIdStr,
                stripeCustomerId: customerId,
                stripeSubscriptionId: subscriptionId,
                stripePriceId: firstItem?.price?.id || "",
                tierId: session.metadata?.tier_id || "",
                status: initialStatus,
                billingPeriod:
                  (session.metadata?.billing_period as
                    | "monthly"
                    | "yearly"
                    | undefined) || "monthly",
                currentPeriodEnd,
                // Only set trialEndsAt if subscription is actually trialing
                trialEndsAt:
                  initialStatus === "trialing" && trialEnd
                    ? new Date(trialEnd * 1000)
                    : null,
                paymentMethodId,
                cardBrand,
                cardLastFour,
                setupFeePaid: session.metadata?.has_setup_fee === "true",
                setupFeeAmount,
                setupFeePaidAt:
                  session.metadata?.has_setup_fee === "true"
                    ? new Date()
                    : null,
                lastPaymentDate: new Date(),
                preferredCurrency: (
                  session.metadata?.currency ||
                  session.currency ||
                  "QAR"
                ).toUpperCase(),
              });

              if (
                session.metadata?.has_setup_fee === "true" &&
                setupFeeAmount
              ) {
                logger.info("Setup fee payment recorded", {
                  amount: setupFeeAmount,
                  currency: session.currency,
                  userId: userIdStr,
                });
              }

              const statusMessage = requiresOTP
                ? `Subscription created (pending OTP verification) for user ${userIdStr}`
                : `Subscription activated for user ${userIdStr}`;
              logger.info(statusMessage, {
                userId: userIdStr,
                subscriptionId,
                cardBrand,
                cardLastFour,
              });
            } else {
              logger.warn("User not found for email", { email: customerEmail });
            }
          }
        } catch (error) {
          logger.error("Error processing checkout.session.completed", {
            error: error instanceof Error ? error.message : String(error),
            stack: error instanceof Error ? error.stack : undefined,
          });
        }
        break;
      }

      case "payment_intent.succeeded": {
        const paymentIntent = event.data.object as Stripe.PaymentIntent;
        logger.info("Payment succeeded", { paymentIntentId: paymentIntent.id });

        try {
          const amount = paymentIntent.amount / 100;
          const currency = paymentIntent.currency;
          const customerId = paymentIntent.customer as string;

          // Get payment method details if available
          let paymentMethodDetails: Record<string, unknown> = {};
          if (paymentIntent.payment_method) {
            const pm = await stripe.paymentMethods.retrieve(
              paymentIntent.payment_method as string,
            );
            if (pm.card) {
              paymentMethodDetails = {
                payment_method_id: pm.id,
                card_brand: pm.card.brand,
                card_last_four: pm.card.last4,
                card_exp_month: pm.card.exp_month,
                card_exp_year: pm.card.exp_year,
              };
            }
          }

          // Track platform fee from Stripe Connect deposits
          if (paymentIntent.application_fee_amount) {
            const orgId = paymentIntent.metadata?.organization_id;
            logger.info("Platform fee collected on deposit", {
              paymentIntentId: paymentIntent.id,
              applicationFee: paymentIntent.application_fee_amount,
              organizationId: orgId,
              transferDestination: paymentIntent.transfer_data?.destination,
            });
          }

          // Find user by stripe customer ID for logging
          const subData = customerId
            ? await convexQuery<Record<string, unknown>>(
                "billing/queries:getByStripeCustomerId",
                { stripeCustomerId: customerId },
              )
            : null;

          logger.info("Payment recorded", {
            amount,
            currency,
            customerId,
            userId: subData?.userId,
            ...paymentMethodDetails,
          });
        } catch (error) {
          logger.error("Error processing payment_intent.succeeded", {
            error: error instanceof Error ? error.message : String(error),
          });
        }
        break;
      }

      case "payment_intent.payment_failed": {
        const paymentIntent = event.data.object as Stripe.PaymentIntent;
        logger.info("Payment failed", { paymentIntentId: paymentIntent.id });

        try {
          const errorMessage =
            paymentIntent.last_payment_error?.message || "Payment failed";

          logger.warn("Payment failure recorded", {
            paymentIntentId: paymentIntent.id,
            errorMessage,
            customerId: paymentIntent.customer,
          });
        } catch (error) {
          logger.error("Error processing payment_intent.payment_failed", {
            error: error instanceof Error ? error.message : String(error),
          });
        }
        break;
      }

      case "customer.subscription.created":
      case "customer.subscription.updated": {
        const subscription = event.data.object as Stripe.Subscription;
        logger.info(`Subscription event: ${event.type}`, {
          subscriptionId: subscription.id,
        });

        try {
          const customerId = subscription.customer as string;
          const status = subscription.status;
          const stripePriceId = subscription.items.data[0]?.price?.id;
          const tierId = subscription.metadata?.tier_id;

          // Find existing subscription in Convex
          const existingSub = await convexQuery<Record<string, unknown>>(
            "billing/queries:getByStripeSubscriptionId",
            { stripeSubscriptionId: subscription.id },
          );

          if (existingSub) {
            const updateArgs: Record<string, unknown> = {
              id: existingSub._id,
              status,
              cancelAtPeriodEnd: subscription.cancel_at_period_end || false,
            };

            const itemPeriodEnd =
              subscription.items?.data?.[0]?.current_period_end;
            if (itemPeriodEnd) {
              updateArgs.currentPeriodEnd = itemPeriodEnd * 1000;
            }

            if (stripePriceId && stripePriceId !== existingSub.stripePriceId) {
              updateArgs.stripePriceId = stripePriceId;
              logger.info("Plan change detected", {
                oldPriceId: existingSub.stripePriceId,
                newPriceId: stripePriceId,
              });
            }

            if (tierId && tierId !== existingSub.tierId) {
              updateArgs.tierId = tierId;
            }

            try {
              await convexMutation(
                "billing/mutations:updateSubscription",
                updateArgs,
              );
            } catch (convexError) {
              logger.error("Failed to update Convex subscription", {
                error: convexError,
              });
            }
          } else {
            logger.warn(
              `Subscription not found in database during ${event.type}`,
              { subscriptionId: subscription.id },
            );
          }

          logger.info(`Subscription ${status} for customer ${customerId}`, {
            customerId,
          });
        } catch (error) {
          logger.error(`Error processing ${event.type}`, {
            error: error instanceof Error ? error.message : String(error),
          });
        }
        break;
      }

      case "customer.subscription.deleted": {
        const subscription = event.data.object as Stripe.Subscription;
        logger.info("Subscription cancelled", {
          subscriptionId: subscription.id,
        });

        try {
          const customerId = subscription.customer as string;

          const existingSub = await convexQuery<Record<string, unknown>>(
            "billing/queries:getByStripeSubscriptionId",
            { stripeSubscriptionId: subscription.id },
          );

          if (existingSub) {
            try {
              await convexMutation("billing/mutations:updateSubscription", {
                id: existingSub._id,
                status: "canceled",
              });
            } catch (convexError) {
              logger.error("Failed to update subscription for cancellation", {
                error: convexError,
              });
            }
          }

          logger.info("Subscription cancelled for customer", {
            customerId,
            subscriptionId: subscription.id,
          });
        } catch (error) {
          logger.error("Error handling subscription cancellation", {
            error: error instanceof Error ? error.message : String(error),
          });
        }
        break;
      }

      case "invoice.payment_succeeded": {
        const invoice = event.data.object as Stripe.Invoice;
        logger.info("Invoice payment succeeded", { invoiceId: invoice.id });

        try {
          const subscriptionId = getSubscriptionIdFromInvoice(invoice);

          const hasProration = invoice.lines.data.some((line) =>
            isProrationLine(line),
          );
          const prorationAmount = invoice.lines.data
            .filter((line) => isProrationLine(line))
            .reduce((sum, line) => sum + line.amount, 0);

          if (subscriptionId) {
            const periodEnd =
              invoice.lines?.data?.[0]?.period?.end ||
              Math.floor(Date.now() / 1000) + 2592000;

            const existingSub = await convexQuery<Record<string, unknown>>(
              "billing/queries:getByStripeSubscriptionId",
              { stripeSubscriptionId: subscriptionId },
            );

            if (existingSub) {
              try {
                await convexMutation("billing/mutations:updateSubscription", {
                  id: existingSub._id,
                  status: "active",
                  currentPeriodEnd: periodEnd * 1000,
                  lastPaymentDate: Date.now(),
                  paymentFailureCount: 0,
                });
              } catch (convexError) {
                logger.error(
                  "Failed to update Convex subscription after payment",
                  { error: convexError },
                );
              }
            }
          }

          if (hasProration) {
            logger.info("Proration payment recorded", {
              totalPaid: invoice.amount_paid || 0,
              prorationAmount: prorationAmount / 100,
              currency: invoice.currency,
            });
          } else {
            logger.info("Invoice paid", {
              amount: invoice.amount_paid || 0,
              currency: invoice.currency,
            });
          }
        } catch (error) {
          logger.error("Error handling invoice payment success", {
            error: error instanceof Error ? error.message : String(error),
          });
        }
        break;
      }

      case "invoice.payment_failed": {
        const invoice = event.data.object as Stripe.Invoice;
        logger.info("Invoice payment failed", { invoiceId: invoice.id });

        try {
          const customerId = invoice.customer as string;
          const subscriptionId = getSubscriptionIdFromInvoice(invoice);
          const attemptCount = invoice.attempt_count || 0;

          if (subscriptionId) {
            const status = attemptCount >= 3 ? "suspended" : "past_due";

            const existingSub = await convexQuery<Record<string, unknown>>(
              "billing/queries:getByStripeSubscriptionId",
              { stripeSubscriptionId: subscriptionId },
            );

            if (existingSub) {
              try {
                await convexMutation("billing/mutations:updateSubscription", {
                  id: existingSub._id,
                  status,
                  paymentFailureCount: attemptCount,
                });
              } catch (convexError) {
                logger.error("Failed to update subscription for failed payment", {
                  error: convexError,
                  subscriptionId,
                });
              }
            }
          }

          logger.warn("Payment failed recorded", {
            attemptCount,
            invoiceId: invoice.id,
            customerId,
          });
        } catch (error) {
          logger.error("Error handling invoice payment failure", {
            error: error instanceof Error ? error.message : String(error),
          });
        }
        break;
      }

      case "charge.refunded": {
        const charge = event.data.object as Stripe.Charge;
        logger.info("Charge refunded", { chargeId: charge.id });

        try {
          const amountRefunded = charge.amount_refunded;

          // Check if we have this refund in our database
          const existingRefund = await convexQuery<Record<string, unknown>>(
            "billing/queries:getByStripeChargeId",
            { stripeChargeId: charge.id },
          );

          if (!existingRefund && charge.refunds?.data?.length) {
            for (const stripeRefund of charge.refunds.data) {
              const refundExists = await convexQuery<Record<string, unknown>>(
                "billing/queries:getByStripeRefundId",
                { stripeRefundId: stripeRefund.id },
              );

              if (!refundExists) {
                logger.info("Refund synced from Stripe", {
                  stripeRefundId: stripeRefund.id,
                  amount: stripeRefund.amount,
                });
              }
            }
          }

          logger.info("Charge refund recorded", {
            chargeId: charge.id,
            amountRefunded,
          });
        } catch (error) {
          logger.error("Error processing charge.refunded", {
            error: error instanceof Error ? error.message : String(error),
          });
        }
        break;
      }

      case "refund.created":
      case "refund.updated": {
        const refund = event.data.object as Stripe.Refund;
        logger.info(`Refund ${event.type}`, { refundId: refund.id });

        try {
          const existingRefund = await convexQuery<Record<string, unknown>>(
            "billing/queries:getByStripeRefundId",
            { stripeRefundId: refund.id },
          );

          if (existingRefund) {
            await convexMutation("billing/mutations:updateRefund", {
              id: existingRefund._id,
              status: refund.status || "pending",
              failureReason: refund.failure_reason || undefined,
              processedAt:
                refund.status === "succeeded" ? Date.now() : undefined,
            });

            logger.info("Refund status updated from webhook", {
              refundId: refund.id,
              status: refund.status,
            });
          } else if (event.type === "refund.created") {
            logger.info("New refund detected from webhook (not in DB)", {
              stripeRefundId: refund.id,
            });
          }
        } catch (error) {
          logger.error(`Error processing ${event.type}`, {
            error: error instanceof Error ? error.message : String(error),
          });
        }
        break;
      }

      case "refund.failed": {
        const refund = event.data.object as Stripe.Refund;
        logger.warn("Refund failed", {
          refundId: refund.id,
          failureReason: refund.failure_reason,
        });

        try {
          const existingRefund = await convexQuery<Record<string, unknown>>(
            "billing/queries:getByStripeRefundId",
            { stripeRefundId: refund.id },
          );

          if (existingRefund) {
            await convexMutation("billing/mutations:updateRefund", {
              id: existingRefund._id,
              status: "failed",
              failureReason: refund.failure_reason || "Unknown failure reason",
            });

            logger.warn("Refund failure recorded", {
              refundId: refund.id,
              failureReason: refund.failure_reason,
            });
          }
        } catch (error) {
          logger.error("Error processing refund.failed", {
            error: error instanceof Error ? error.message : String(error),
          });
        }
        break;
      }

      // -----------------------------------------------------------------------
      // Stripe Connect Events
      // -----------------------------------------------------------------------
      case "account.updated": {
        const account = event.data.object as Stripe.Account;
        logger.info("Connect account updated", { accountId: account.id });

        try {
          const org = await convexQuery<Record<string, unknown>>(
            "organizations/queries:getOrganizationByConnectAccountId",
            { stripeConnectAccountId: account.id },
          );

          if (org) {
            let newStatus = "pending";
            if (account.charges_enabled && account.payouts_enabled) {
              newStatus = "active";
            } else if (account.details_submitted) {
              newStatus = "restricted";
            }

            if (org.stripeConnectStatus !== newStatus) {
              await convexMutation(
                "organizations/mutations:updateOrganizationNoAuth",
                {
                  organizationId: org._id as string,
                  stripeConnectStatus: newStatus,
                },
              );
              logger.info("Connect account status updated", {
                organizationId: org._id,
                oldStatus: org.stripeConnectStatus,
                newStatus,
                chargesEnabled: account.charges_enabled,
                payoutsEnabled: account.payouts_enabled,
              });
            }
          } else {
            logger.warn("No organization found for Connect account", {
              accountId: account.id,
            });
          }
        } catch (error) {
          logger.error("Error processing account.updated", {
            error: error instanceof Error ? error.message : String(error),
          });
        }
        break;
      }

      default:
        logger.info("Unhandled Stripe event type", { eventType: event.type });
    }

    // Always return 200 to acknowledge receipt
    return NextResponse.json({ received: true, eventType: event.type });
  } catch (error) {
    logger.error("Webhook handler error", {
      error: error instanceof Error ? error.message : String(error),
      stack: error instanceof Error ? error.stack : undefined,
    });
    return NextResponse.json(
      { error: "Webhook handler failed" },
      { status: 500 },
    );
  }
}

// Disable body parsing for webhook signature verification
export const runtime = "nodejs";
export const dynamic = "force-dynamic";
