import { NextRequest, NextResponse } from "next/server";
import { stripe } from "@/lib/stripe";
import { prisma } from "@/lib/db";
import { auth } from "@/lib/auth";
import { getAuthenticatedConvexUser } from "@/lib/convex-auth-state";
import { logger } from "@/lib/logger";
import {
  getStripePriceId,
  getSetupFeePriceId,
  getSetupFeeAmount,
} from "@/lib/stripe-prices";
import { applyRateLimit, rateLimiters } from "@/lib/rate-limiter";
import { convexMutation } from "@/lib/convex-client";

/**
 * POST /api/subscriptions/create-checkout
 *
 * Creates a Stripe checkout session for existing authenticated users
 * This endpoint is for users who already have an account and want to upgrade/subscribe
 *
 * Request body:
 * {
 *   tierId: "tier1" | "tier2" | "tier3" | "tier4" | "tier5",
 *   billingPeriod: "monthly" | "yearly",
 *   currency: "QAR",
 *   language: "en" | "ar"
 * }
 *
 * Key Differences from Signup Checkout:
 * - Uses authenticated user's info (no need for email/name in request)
 * - Only charges setup fee if no previous Stripe customer ID
 * - Redirects to dashboard instead of signup success
 */

// Force dynamic rendering - don't pre-render at build time
export const dynamic = "force-dynamic";
export const runtime = "nodejs";

interface CheckoutRequestBody {
  tierId: string;
  billingPeriod: "monthly" | "yearly";
  currency: string;
  language?: string;
}

// Only QAR is currently supported
const ALLOWED_CURRENCIES = ["QAR"];

async function persistCheckoutContext(
  params: {
    userId: string;
    selectedPackage: string;
    preferredCurrency: string;
    selectedBillingPeriod: "monthly" | "yearly";
    stripeCustomerId: string;
  },
  requestLogger: ReturnType<typeof logger.scope>,
) {
  try {
    await convexMutation("auth/mutations:updateUserNoAuth", {
      userId: params.userId,
      selectedPackage: params.selectedPackage,
      preferredCurrency: params.preferredCurrency,
      selectedBillingPeriod: params.selectedBillingPeriod,
      stripeCustomerId: params.stripeCustomerId,
    });

    requestLogger.info("Persisted checkout context to Convex user", {
      userId: params.userId,
      selectedPackage: params.selectedPackage,
      preferredCurrency: params.preferredCurrency,
      selectedBillingPeriod: params.selectedBillingPeriod,
      stripeCustomerId: params.stripeCustomerId,
    });
    return;
  } catch (convexError) {
    requestLogger.warn(
      "Direct Convex user sync failed, retrying through adapter",
      {
        userId: params.userId,
        error:
          convexError instanceof Error
            ? convexError.message
            : String(convexError),
      },
    );
  }

  await prisma.users.update({
    where: { id: params.userId },
    data: {
      selectedPackage: params.selectedPackage,
      preferredCurrency: params.preferredCurrency,
      // Note: selectedBillingPeriod only exists in Convex, not Prisma users table
      stripeCustomerId: params.stripeCustomerId,
    },
  });
}

export async function POST(request: NextRequest) {
  const requestId = `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
  const requestLogger = logger.scope(
    `subscriptions:create-checkout:${requestId}`,
  );

  try {
    // Apply rate limiting: 10 requests per 15 minutes per IP
    const rateLimitResponse = await applyRateLimit(
      request,
      rateLimiters.checkout,
    );
    if (rateLimitResponse) {
      return rateLimitResponse;
    }

    // 1. Authenticate user (supports NextAuth session + Clerk fallback)
    const user = await getAuthenticatedConvexUser(request, auth);
    if (!user) {
      requestLogger.warn("Unauthenticated checkout attempt", { requestId });
      return NextResponse.json(
        {
          error: "Authentication required",
          errorAr: "المصادقة مطلوبة",
          code: "UNAUTHENTICATED",
        },
        { status: 401 },
      );
    }

    requestLogger.info("Authenticated user for checkout", {
      userId: user.id,
      email: user.email,
    });

    // 2. Parse and validate request body
    const body = (await request.json()) as CheckoutRequestBody;
    const { tierId, billingPeriod, currency = "QAR", language = "en" } = body;

    requestLogger.info("Checkout request received", {
      userId: user.id,
      tierId,
      billingPeriod,
      currency,
      language,
    });

    // Input validation
    const validationErrors = validateCheckoutInput(body);
    if (validationErrors.length > 0) {
      requestLogger.warn("Validation failed", {
        errors: validationErrors,
        userId: user.id,
      });
      return NextResponse.json(
        {
          error: "Invalid request parameters",
          errorAr: "معاملات الطلب غير صالحة",
          code: "VALIDATION_ERROR",
          details: validationErrors,
        },
        { status: 400 },
      );
    }

    // 3. Fetch Stripe price ID
    let stripePriceId: string | null;
    try {
      stripePriceId = await getStripePriceId(tierId, billingPeriod, currency);
    } catch (priceError) {
      if (
        priceError instanceof Error &&
        priceError.message.includes("Multi-currency not yet supported")
      ) {
        requestLogger.warn("Non-QAR currency requested", {
          userId: user.id,
          requestedCurrency: currency,
          tierId,
          billingPeriod,
        });
        return NextResponse.json(
          {
            error: "Only QAR currency is currently supported",
            errorAr: "فقط الريال القطري (QAR) مدعوم حاليًا",
            code: "INVALID_CURRENCY",
          },
          { status: 400 },
        );
      }

      requestLogger.error("Error fetching price ID", priceError);
      return NextResponse.json(
        {
          error: "Failed to fetch pricing information",
          errorAr: "فشل في جلب معلومات التسعير",
          code: "PRICE_FETCH_ERROR",
        },
        { status: 500 },
      );
    }

    if (!stripePriceId) {
      requestLogger.error("No price found for tier/period/currency", {
        tierId,
        billingPeriod,
        currency,
      });
      return NextResponse.json(
        {
          error: "Price not found for selected plan",
          errorAr: "لم يتم العثور على السعر للخطة المحددة",
          code: "PRICE_NOT_FOUND",
        },
        { status: 404 },
      );
    }

    requestLogger.info("Price ID fetched successfully", {
      stripePriceId,
      tierId,
      billingPeriod,
    });

    // 4. Get or create Stripe customer
    let customerId = user.stripeCustomerId;

    if (!customerId) {
      try {
        const customer = await stripe.customers.create({
          email: user.email,
          name: user.name || undefined,
          metadata: {
            user_id: user.id,
            tier_id: tierId,
            billing_period: billingPeriod,
            preferred_currency: currency,
          },
        });
        customerId = customer.id;

        requestLogger.info("Stripe customer created", {
          customerId,
          userId: user.id,
        });
      } catch (stripeError) {
        requestLogger.error("Failed to create Stripe customer", stripeError);
        return NextResponse.json(
          {
            error: "Failed to create customer account",
            errorAr: "فشل في إنشاء حساب العميل",
            code: "CUSTOMER_CREATION_FAILED",
          },
          { status: 500 },
        );
      }
    } else {
      requestLogger.info("Using existing Stripe customer", {
        customerId,
        userId: user.id,
      });
    }

    if (!customerId) {
      throw new Error("Stripe customer ID missing after creation step");
    }

    // Persist checkout context (non-fatal — don't block checkout if this fails)
    try {
      await persistCheckoutContext(
        {
          userId: user.id,
          selectedPackage: tierId,
          preferredCurrency: currency,
          selectedBillingPeriod: billingPeriod,
          stripeCustomerId: customerId,
        },
        requestLogger,
      );
    } catch (persistError) {
      requestLogger.warn("Failed to persist checkout context (non-fatal)", {
        userId: user.id,
        error:
          persistError instanceof Error
            ? persistError.message
            : String(persistError),
      });
    }

    // 5. Calculate setup fee (only if user has never paid a setup fee)
    // Use Convex user fields instead of querying Prisma subscriptions table
    const shouldChargeSetupFee = !user.setupFeePaid;
    const isTrialOver = !!user.isTrialOver;

    requestLogger.info("Trial/setup fee status from Convex user", {
      userId: user.id,
      isTrialOver,
      setupFeePaid: !!user.setupFeePaid,
      shouldChargeSetupFee,
    });

    const lineItems: Array<{ price: string; quantity: number }> = [
      {
        price: stripePriceId,
        quantity: 1,
      },
    ];

    if (shouldChargeSetupFee) {
      const setupFeePriceId = getSetupFeePriceId(tierId);
      if (setupFeePriceId) {
        lineItems.push({
          price: setupFeePriceId,
          quantity: 1,
        });
        requestLogger.info("Setup fee added (first-time payment)", {
          setupFeePriceId,
          tierId,
          userId: user.id,
        });
      } else {
        requestLogger.warn("Setup fee price ID not found", { tierId });
      }
    } else {
      requestLogger.info("Setup fee waived (already paid)", {
        userId: user.id,
        setupFeePaid: user.setupFeePaid,
      });
    }

    // 6. Create Stripe checkout session (trial only for first-time users)
    let checkoutSession;
    try {
      const subscriptionData: Record<string, unknown> = {
        metadata: {
          user_id: user.id,
          tier_id: tierId,
          billing_period: billingPeriod,
          currency,
          language: language,
          is_upgrade: "true",
          has_setup_fee: shouldChargeSetupFee ? "true" : "false",
          setup_fee_amount: shouldChargeSetupFee
            ? String(getSetupFeeAmount(tierId))
            : "0",
        },
      };

      // Only give 14-day trial to first-time users who haven't had a trial before
      if (!isTrialOver) {
        subscriptionData.trial_period_days = 14;
        requestLogger.info("14-day trial applied (first-time user)", {
          userId: user.id,
        });
      } else {
        requestLogger.info("Trial skipped (returning user, isTrialOver=true)", {
          userId: user.id,
        });
      }

      checkoutSession = await stripe.checkout.sessions.create({
        mode: "subscription",
        customer: customerId,
        client_reference_id: user.id,
        line_items: lineItems,
        metadata: {
          user_id: user.id,
          tier_id: tierId,
          billing_period: billingPeriod,
          currency,
          language: language,
          is_upgrade: "true",
          has_setup_fee: shouldChargeSetupFee ? "true" : "false",
          setup_fee_amount: shouldChargeSetupFee
            ? String(getSetupFeeAmount(tierId))
            : "0",
        },
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        subscription_data: subscriptionData as any,
        success_url: `${process.env.NEXT_PUBLIC_APP_URL || "http://localhost:9000"}/${language}/payment/success?session_id={CHECKOUT_SESSION_ID}`,
        cancel_url: `${process.env.NEXT_PUBLIC_APP_URL || "http://localhost:9000"}/${language}/dashboard?payment=cancelled`,
        allow_promotion_codes: true,
        payment_method_types: ["card"],
        billing_address_collection: "required",
      });

      requestLogger.info("Stripe checkout session created", {
        sessionId: checkoutSession.id,
        userId: user.id,
        tierId,
        billingPeriod,
        hasSetupFee: shouldChargeSetupFee,
      });
    } catch (stripeError) {
      requestLogger.error("Failed to create checkout session", stripeError);
      return NextResponse.json(
        {
          error: "Failed to create checkout session",
          errorAr: "فشل في إنشاء جلسة الدفع",
          code: "SESSION_CREATION_FAILED",
        },
        { status: 500 },
      );
    }

    // 7. Return session URL and ID
    return NextResponse.json({
      sessionUrl: checkoutSession.url,
      sessionId: checkoutSession.id,
      success: true,
    });
  } catch (error) {
    requestLogger.error("Unexpected checkout error", error);
    return NextResponse.json(
      {
        error: "An unexpected error occurred",
        errorAr: "حدث خطأ غير متوقع",
        code: "UNKNOWN_ERROR",
      },
      { status: 500 },
    );
  }
}

/**
 * Validate checkout request input
 */
function validateCheckoutInput(body: Partial<CheckoutRequestBody>): string[] {
  const errors: string[] = [];

  // Validate tierId
  if (!body.tierId) {
    errors.push("tierId is required");
  } else if (
    !["tier1", "tier2", "tier3", "tier4", "tier5"].includes(body.tierId)
  ) {
    errors.push("tierId must be tier1-tier5");
  }

  // Validate billingPeriod
  if (!body.billingPeriod) {
    errors.push("billingPeriod is required");
  } else if (!["monthly", "yearly"].includes(body.billingPeriod)) {
    errors.push("billingPeriod must be monthly or yearly");
  }

  // Validate currency
  if (!body.currency) {
    errors.push("currency is required");
  } else if (!ALLOWED_CURRENCIES.includes(body.currency.toUpperCase())) {
    errors.push(`currency must be one of: ${ALLOWED_CURRENCIES.join(", ")}`);
  }

  // Validate language (optional, but if provided must be valid)
  if (body.language && !["en", "ar"].includes(body.language)) {
    errors.push('language must be "en" or "ar"');
  }

  return errors;
}
