import { NextRequest, NextResponse } from "next/server";
import Stripe from "stripe";
import { stripe } from "@/lib/stripe";
import { logger } from "@/lib/logger";
import { createId } from "@paralleldrive/cuid2";
import { auth } from "@/lib/auth";
import {
  getAuthenticatedConvexUser,
  getConvexUserByAppUserId,
  getConvexUserByEmail,
  type ConvexAppUser,
} from "@/lib/convex-auth-state";
import { convexMutation, convexQuery } from "@/lib/convex-client";

/**
 * GET /api/payment/verify-session?session_id=cs_...
 *
 * Verifies a Stripe checkout session and ensures subscription exists in Convex.
 * Pure Convex — no Prisma adapter involvement.
 */

export const dynamic = "force-dynamic";
export const runtime = "nodejs";

const ACTIVE_SUBSCRIPTION_STATUSES = new Set([
  "active",
  "trialing",
  "past_due",
]);

async function findActiveConvexSubscription(
  userId: string,
): Promise<Record<string, unknown> | null> {
  try {
    const sub = await convexQuery<Record<string, unknown>>(
      "billing/queries:getActiveSubscription",
      { userId },
    );
    return sub || null;
  } catch {
    return null;
  }
}

async function findConvexSubscriptionByStripeId(
  stripeSubscriptionId: string,
): Promise<Record<string, unknown> | null> {
  try {
    const sub = await convexQuery<Record<string, unknown>>(
      "billing/queries:getByStripeSubscriptionId",
      { stripeSubscriptionId },
    );
    return sub || null;
  } catch {
    return null;
  }
}

async function resolveCheckoutUser(params: {
  authenticatedUser: ConvexAppUser | null;
  sessionUserId: string | null;
  clientReferenceId: string | null;
  customerEmail: string | null;
  customerId: string | null;
}): Promise<ConvexAppUser | null> {
  const {
    authenticatedUser,
    sessionUserId,
    clientReferenceId,
    customerEmail,
  } = params;

  const candidateIds = [sessionUserId, clientReferenceId].filter(
    (value): value is string => Boolean(value),
  );

  for (const candidateId of candidateIds) {
    if (authenticatedUser?.id === candidateId) return authenticatedUser;
    const byId = await getConvexUserByAppUserId(candidateId).catch(() => null);
    if (byId) return byId;
  }

  if (customerEmail) {
    if (authenticatedUser?.email?.toLowerCase() === customerEmail.toLowerCase())
      return authenticatedUser;
    const byEmail = await getConvexUserByEmail(customerEmail).catch(() => null);
    if (byEmail) return byEmail;
  }

  return authenticatedUser || null;
}

export async function GET(request: NextRequest) {
  const requestId = `verify_${Date.now()}`;

  try {
    const authenticatedUser = await getAuthenticatedConvexUser(
      request,
      auth,
    ).catch(() => null);

    const { searchParams } = new URL(request.url);
    const sessionId = searchParams.get("session_id");

    if (!sessionId) {
      return NextResponse.json(
        { error: "Missing session_id parameter" },
        { status: 400 },
      );
    }

    // Retrieve checkout session from Stripe
    let session;
    try {
      session = await stripe.checkout.sessions.retrieve(sessionId, {
        expand: ["subscription", "subscription.default_payment_method"],
      });
    } catch (stripeError) {
      // Fallback: check if user already has active subscription in Convex
      if (authenticatedUser) {
        const existingSub = await findActiveConvexSubscription(authenticatedUser.id);
        if (existingSub && ACTIVE_SUBSCRIPTION_STATUSES.has(existingSub.status as string)) {
          return NextResponse.json({
            success: true,
            hasActiveSubscription: true,
            subscription: {
              id: existingSub._id,
              status: existingSub.status,
              tierId: existingSub.tierId,
            },
            source: "convex_fallback",
          });
        }
      }

      logger.error("[VerifySession] Stripe session retrieval failed", {
        requestId,
        error: stripeError instanceof Error ? stripeError.message : String(stripeError),
      });
      return NextResponse.json({ error: "Invalid or expired session" }, { status: 400 });
    }

    const customerId =
      typeof session.customer === "string"
        ? session.customer
        : session.customer?.id || "";
    const customerEmail =
      session.customer_details?.email || session.customer_email || null;

    const resolvedUser = await resolveCheckoutUser({
      authenticatedUser,
      sessionUserId: session.metadata?.user_id || null,
      clientReferenceId: session.client_reference_id || null,
      customerEmail,
      customerId,
    });

    if (!resolvedUser) {
      return NextResponse.json(
        { error: "Invalid session — missing user reference" },
        { status: 400 },
      );
    }

    const userId = resolvedUser.id;

    // Check payment status
    if (
      session.payment_status !== "paid" &&
      session.payment_status !== "no_payment_required"
    ) {
      return NextResponse.json({
        success: false,
        hasActiveSubscription: false,
        paymentStatus: session.payment_status,
        message: "Payment not completed",
      });
    }

    if (!session.subscription) {
      return NextResponse.json(
        { error: "No subscription found in session" },
        { status: 400 },
      );
    }

    // Get subscription details from Stripe
    const stripeSubscription =
      typeof session.subscription === "string"
        ? await stripe.subscriptions.retrieve(session.subscription, {
            expand: ["default_payment_method"],
          })
        : session.subscription;

    const stripeSubscriptionId = stripeSubscription.id;
    const tierId = session.metadata?.tier_id || stripeSubscription.metadata?.tier_id || "";
    const billingPeriod = (session.metadata?.billing_period || "monthly") as "monthly" | "yearly";
    const preferredCurrency = (session.metadata?.currency || "QAR").toUpperCase();
    const stripePriceId = stripeSubscription.items?.data?.[0]?.price?.id || "";
    const subscriptionStatus =
      stripeSubscription.status === "trialing" || stripeSubscription.status === "active"
        ? stripeSubscription.status
        : "active";

    // Convert timestamps to epoch ms
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const sub = stripeSubscription as any;
    const currentPeriodEnd = sub.current_period_end
      ? sub.current_period_end * 1000
      : Date.now() + 30 * 24 * 60 * 60 * 1000;
    const trialEndsAt = sub.trial_end
      ? sub.trial_end * 1000
      : undefined;

    // Extract payment method
    let paymentMethodId: string | undefined;
    let cardBrand: string | undefined;
    let cardLastFour: string | undefined;

    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;
      }
    }

    // Check if subscription already exists in Convex
    const existingSub = await findConvexSubscriptionByStripeId(stripeSubscriptionId);

    if (existingSub?._id) {
      // Update existing subscription
      try {
        await convexMutation("billing/mutations:updateSubscription", {
          id: existingSub._id,
          status: subscriptionStatus,
          tierId,
          stripePriceId,
          billingPeriod,
          currentPeriodEnd,
          trialEndsAt,
          paymentMethodId,
          cardBrand,
          cardLastFour,
          lastPaymentDate: Date.now(),
        });
      } catch (updateErr) {
        logger.warn("[VerifySession] Convex subscription update failed", {
          requestId,
          error: updateErr instanceof Error ? updateErr.message : String(updateErr),
        });
      }

      // Update user state
      try {
        await convexMutation("auth/mutations:updateUserNoAuth", {
          userId,
          stripeCustomerId: customerId,
          selectedPackage: tierId,
          preferredCurrency,
          selectedBillingPeriod: billingPeriod,
          isTrialOver: true,
        });
      } catch {
        // non-fatal
      }

      return NextResponse.json({
        success: true,
        hasActiveSubscription: ACTIVE_SUBSCRIPTION_STATUSES.has(subscriptionStatus),
        subscription: {
          id: existingSub._id,
          status: subscriptionStatus,
          tierId,
        },
        source: "existing",
      });
    }

    // Create new subscription directly in Convex
    logger.info("[VerifySession] Creating subscription in Convex", {
      requestId,
      stripeSubscriptionId,
      userId,
    });

    try {
      const newSubId = await convexMutation("billing/mutations:createSubscription", {
        prismaId: createId(),
        userId,
        stripeCustomerId: customerId,
        stripeSubscriptionId,
        stripePriceId,
        tierId,
        status: subscriptionStatus,
        billingPeriod,
        currentPeriodEnd,
        trialEndsAt,
        paymentMethodId,
        cardBrand,
        cardLastFour,
        lastPaymentDate: Date.now(),
      });

      logger.info("[VerifySession] Subscription created in Convex", {
        requestId,
        subscriptionId: newSubId,
      });
    } catch (convexCreateError) {
      logger.error("[VerifySession] Convex subscription create failed", {
        requestId,
        error:
          convexCreateError instanceof Error
            ? convexCreateError.message
            : String(convexCreateError),
      });
    }

    // Update user state
    try {
      await convexMutation("auth/mutations:updateUserNoAuth", {
        userId,
        stripeCustomerId: customerId,
        selectedPackage: tierId,
        preferredCurrency,
        selectedBillingPeriod: billingPeriod,
        isTrialOver: true,
      });
    } catch {
      // non-fatal
    }

    return NextResponse.json({
      success: true,
      hasActiveSubscription: ACTIVE_SUBSCRIPTION_STATUSES.has(subscriptionStatus),
      subscription: {
        id: stripeSubscriptionId,
        status: subscriptionStatus,
        tierId,
      },
      source: "created_convex",
      message: "Subscription verified and saved to Convex",
    });
  } catch (error) {
    logger.error("[VerifySession] Unexpected error", {
      requestId,
      error: error instanceof Error ? error.message : String(error),
      stack: error instanceof Error ? error.stack : undefined,
    });

    return NextResponse.json(
      { error: "Failed to verify session" },
      { status: 500 },
    );
  }
}
