import { NextRequest, NextResponse } from "next/server";
import { auth } from "@/lib/auth";
import { logger } from "@/lib/logger";
import { PRICING_TIERS } from "@/lib/config/pricing-tiers";
import {
  CURRENCY_RATES,
  calculateYearlyTotal,
  getDaysUntilBilling,
  getTierPriceQAR,
} from "@/lib/utils/pricing-helpers";
import { getAuthenticatedConvexUser } from "@/lib/convex-auth-state";
import { getActiveConvexSubscription } from "@/lib/convex-billing-state";
import { convexQuery } from "@/lib/convex-client";
import { previewPlanChange } from "@/lib/stripe-subscription-billing";
import {
  type AvailablePlanInfo,
  type BillingPeriod,
  type PlanChangePreviewResponse,
  type ProrationBreakdown,
  type TierId,
  isValidBillingPeriod,
  isValidTierId,
  TIER_ORDER,
} from "@/lib/types/plan-change.types";

const QAR_RATE = CURRENCY_RATES.QAR;

async function resolveBillableSubscription(userId: string) {
  const directSubscription = await getActiveConvexSubscription(userId);
  if (directSubscription) {
    return directSubscription;
  }

  const orgState = await convexQuery<{
    organization: { ownerId: string };
  }>("organizations/queries:getOrganizationStateByUserId", {
    userId,
  });

  if (
    orgState?.organization?.ownerId &&
    orgState.organization.ownerId !== userId
  ) {
    return await getActiveConvexSubscription(orgState.organization.ownerId);
  }

  return null;
}

function buildPlanInfo(
  tierId: TierId,
  billingPeriod: BillingPeriod,
  currentTierId: TierId,
): AvailablePlanInfo {
  const tier = PRICING_TIERS.find((item) => item.id === tierId);
  if (!tier) {
    throw new Error(`Invalid tier: ${tierId}`);
  }

  const monthlyQAR = tier.priceGBP * QAR_RATE;
  const priceInCurrency =
    billingPeriod === "yearly" ? calculateYearlyTotal(monthlyQAR) : monthlyQAR;

  return {
    id: tierId,
    nameEn: tier.nameEn,
    nameAr: tier.nameAr,
    priceGBP: tier.priceGBP,
    priceInCurrency: Math.round(priceInCurrency),
    currency: "QAR",
    billingPeriod,
    featuresEn: tier.featuresEn,
    featuresAr: tier.featuresAr,
    isCurrent: tierId === currentTierId,
    order: TIER_ORDER[tierId],
    popular: tier.popular,
  };
}

export async function GET(request: NextRequest) {
  try {
    const user = await getAuthenticatedConvexUser(request, auth);
    if (!user) {
      return NextResponse.json(
        { error: "Unauthorized", code: "UNAUTHORIZED" },
        { status: 401 },
      );
    }

    const { searchParams } = new URL(request.url);
    const newTierId = searchParams.get("newTierId");
    const billingPeriodParam = searchParams.get("billingPeriod");

    if (!newTierId || !isValidTierId(newTierId)) {
      return NextResponse.json(
        { error: "Invalid tier ID", code: "INVALID_TIER" },
        { status: 400 },
      );
    }

    const subscription = await resolveBillableSubscription(user.id);
    if (!subscription) {
      return NextResponse.json(
        {
          error: "No active subscription found",
          code: "NO_ACTIVE_SUBSCRIPTION",
        },
        { status: 404 },
      );
    }

    const currentTierId = subscription.tierId as TierId;
    const currentBillingPeriod = subscription.billingPeriod as BillingPeriod;

    if (!isValidTierId(currentTierId)) {
      return NextResponse.json(
        { error: "Invalid subscription configuration", code: "INVALID_TIER" },
        { status: 500 },
      );
    }

    if (newTierId === currentTierId) {
      return NextResponse.json(
        { error: "Already on this plan", code: "SAME_PLAN" },
        { status: 400 },
      );
    }

    const billingPeriod =
      billingPeriodParam && isValidBillingPeriod(billingPeriodParam)
        ? billingPeriodParam
        : currentBillingPeriod;

    const currentPeriodEnd = new Date(subscription.currentPeriodEnd);
    const daysRemaining = getDaysUntilBilling(currentPeriodEnd);

    let stripePreview = null;
    try {
      stripePreview = await previewPlanChange({
        subscriptionId: subscription._id,
        newTierId,
        billingPeriod,
      });
    } catch (stripeError) {
      logger.error(
        "Stripe preview failed, falling back to manual calculation",
        {
          error:
            stripeError instanceof Error
              ? stripeError.message
              : "Unknown error",
        },
      );
    }

    const currentPlan = buildPlanInfo(
      currentTierId,
      currentBillingPeriod,
      currentTierId,
    );
    const newPlan = buildPlanInfo(newTierId, billingPeriod, currentTierId);

    const proration: ProrationBreakdown = stripePreview
      ? {
          daysRemaining,
          totalDaysInPeriod: billingPeriod === "yearly" ? 365 : 30,
          currentDailyRate: 0,
          newDailyRate: 0,
          creditFromCurrent: stripePreview.creditFromCurrent,
          chargeForNew: stripePreview.chargeForNew,
          netAmount: stripePreview.netAmount,
        }
      : {
          daysRemaining,
          totalDaysInPeriod: billingPeriod === "yearly" ? 365 : 30,
          currentDailyRate: Math.round(
            getTierPriceQAR(currentTierId, billingPeriod) /
              (billingPeriod === "yearly" ? 365 : 30),
          ),
          newDailyRate: Math.round(
            getTierPriceQAR(newTierId, billingPeriod) /
              (billingPeriod === "yearly" ? 365 : 30),
          ),
          creditFromCurrent:
            Math.round(
              getTierPriceQAR(currentTierId, billingPeriod) /
                (billingPeriod === "yearly" ? 365 : 30),
            ) * daysRemaining,
          chargeForNew:
            Math.round(
              getTierPriceQAR(newTierId, billingPeriod) /
                (billingPeriod === "yearly" ? 365 : 30),
            ) * daysRemaining,
          netAmount:
            Math.round(
              getTierPriceQAR(newTierId, billingPeriod) /
                (billingPeriod === "yearly" ? 365 : 30),
            ) *
              daysRemaining -
            Math.round(
              getTierPriceQAR(currentTierId, billingPeriod) /
                (billingPeriod === "yearly" ? 365 : 30),
            ) *
              daysRemaining,
        };

    const isUpgrade = TIER_ORDER[newTierId] > TIER_ORDER[currentTierId];
    const nextBillingAmount = getTierPriceQAR(newTierId, billingPeriod);
    const netAmountQAR = Math.abs(proration.netAmount) / 100;

    const response: PlanChangePreviewResponse = {
      success: true,
      preview: {
        currentPlan,
        newPlan,
        proration,
        isUpgrade,
        nextBillingDate: currentPeriodEnd.toISOString(),
        nextBillingAmount,
        currency: "QAR",
        summary: {
          en: isUpgrade
            ? `You will be charged QAR ${netAmountQAR.toFixed(2)} now for the upgrade. Your next billing of QAR ${(nextBillingAmount / 100).toFixed(2)} will be on ${currentPeriodEnd.toLocaleDateString("en-US", { month: "long", day: "numeric", year: "numeric" })}.`
            : `You will receive a credit of QAR ${netAmountQAR.toFixed(2)} applied to your next bill. Your next billing will be QAR ${(nextBillingAmount / 100).toFixed(2)} on ${currentPeriodEnd.toLocaleDateString("en-US", { month: "long", day: "numeric", year: "numeric" })}.`,
          ar: isUpgrade
            ? `سيتم خصم ${netAmountQAR.toFixed(2)} ر.ق الآن للترقية. فاتورتك القادمة بقيمة ${(nextBillingAmount / 100).toFixed(2)} ر.ق ستكون في ${currentPeriodEnd.toLocaleDateString("ar-QA", { month: "long", day: "numeric", year: "numeric" })}.`
            : `ستحصل على رصيد بقيمة ${netAmountQAR.toFixed(2)} ر.ق يُطبق على فاتورتك القادمة. فاتورتك القادمة ستكون ${(nextBillingAmount / 100).toFixed(2)} ر.ق في ${currentPeriodEnd.toLocaleDateString("ar-QA", { month: "long", day: "numeric", year: "numeric" })}.`,
        },
      },
    };

    return NextResponse.json(response);
  } catch (error) {
    logger.error("Plan change preview error", {
      error: error instanceof Error ? error.message : "Unknown error",
      stack: error instanceof Error ? error.stack : undefined,
    });

    return NextResponse.json(
      { error: "Failed to generate preview", code: "STRIPE_ERROR" },
      { status: 500 },
    );
  }
}
