import { useSearchParams } from 'next/navigation';
import { useEffect, useMemo, useRef, useState } from 'react';
import { twMerge } from 'tailwind-merge';
import { useResizeObserver } from 'usehooks-ts';

import {
  getAnnualPriceForPlanAndCurrency,
  getMonthlyPriceForPlanAndCurrency,
  getPriceForPlanAndCurrency,
} from '@/app/(root)/account/AuraSubscriptions/CurrencySelector';
import { Currency } from '@/app/(root)/account/constants';
import RadioGroupWithBadges from '@/components/RadioGroupWithBadges/RadioGroupWithBadges';
import { AuraSubscriptionCard } from '@/components/card/AuraSubscriptionCard';
import { AXON_ITEM_CATEGORY_ID } from '@/components/ga4/constants';
import {
  createAxonItemVariantIdForSubscription,
  useAxon,
} from '@/components/ga4/useAxon';
import { useDefaultBillingPeriod } from '@/hooks/useDefaultBillingPeriod';
import { useEligibleDiscounts } from '@/hooks/useEligibleDiscounts';
import { CHECKOUT_SOURCE, type CheckoutSource } from '@/lib/checkoutSource';
import logWebUserEvent from '@/logging/logWebUserEvent';
import {
  CtaButtons,
  PlanKey,
  SubscriptionInfo,
  UsagePlanDescription,
  UsagePlanSchema,
} from '@/state/sessionStore';
import { SubscriptionPeriod } from '@/utils/session';

const { Annual: ANNUAL, Monthly: MONTHLY } = SubscriptionPeriod;

interface PlansProps {
  plans: UsagePlanSchema[];
  currentSubscription: SubscriptionInfo | null;
  usagePlanDescriptions: Record<string, UsagePlanDescription>;
  ctaButtons?: CtaButtons | null;
  selectedCurrency: Currency;
  checkoutSource?: CheckoutSource;
}

export const Plans = ({
  plans,
  currentSubscription,
  usagePlanDescriptions,
  ctaButtons,
  selectedCurrency,
  checkoutSource = CHECKOUT_SOURCE.ACCOUNT_PAGE,
}: PlansProps) => {
  const urlParams = useSearchParams();
  const { publishViewItemEvent: publishAxonViewItemEvent } = useAxon();
  const { data: eligibleDiscountsResult } = useEligibleDiscounts();
  const defaultPeriod = useDefaultBillingPeriod();

  const urlPeriod = urlParams.get('period') as SubscriptionPeriod;
  const [period, setPeriod] = useState<SubscriptionPeriod>(
    urlPeriod || defaultPeriod
  );

  // Update period when defaultPeriod changes (e.g., when Statsig loads)
  useEffect(() => {
    // Only update if there's no URL parameter override
    if (!urlPeriod) {
      setPeriod(defaultPeriod);
    }
  }, [defaultPeriod, urlPeriod]);

  useEffect(() => {
    // Find the most popular plan (pro) for view_item event
    const proPlan = plans.find((plan) => plan.plan_key === PlanKey.Pro);

    if (!proPlan) return;

    const currency = selectedCurrency;
    const monthlyPrice = getMonthlyPriceForPlanAndCurrency(proPlan, currency);
    const annualPrice = getAnnualPriceForPlanAndCurrency(proPlan, currency);
    if (period === MONTHLY && Number.isNaN(monthlyPrice)) return;
    if (period === ANNUAL && Number.isNaN(annualPrice)) return;

    const price = period === ANNUAL ? annualPrice : monthlyPrice;

    const items = [
      {
        item_variant_id: createAxonItemVariantIdForSubscription(
          proPlan.plan_key,
          period
        ),
        item_id: proPlan.plan_key,
        item_name: proPlan.name,
        price,
        quantity: 1,
        item_category_id: AXON_ITEM_CATEGORY_ID,
      },
    ];

    publishAxonViewItemEvent({
      currency: Currency.USD,
      value:
        period === ANNUAL
          ? proPlan.annual_price_usd
          : proPlan.monthly_price_usd,
      items,
    });
  }, [publishAxonViewItemEvent, period, plans, selectedCurrency]);

  const getPriceForPlan = (
    plan: UsagePlanSchema,
    period: SubscriptionPeriod
  ) => {
    const currency = selectedCurrency;
    if (period === ANNUAL) {
      return (
        getPriceForPlanAndCurrency(plan, currency, SubscriptionPeriod.Annual) /
        12
      );
    }
    return getPriceForPlanAndCurrency(
      plan,
      currency,
      SubscriptionPeriod.Monthly
    );
  };

  // Sort plans by monthly price, and filter out free plan for active subscribers
  const sortedPlans = useMemo<UsagePlanSchema[]>(() => {
    if (!plans) return [];

    const currency = selectedCurrency;

    // Filter out free plan if user is an active subscriber and feature flag is enabled
    const filteredPlans = currentSubscription?.is_active
      ? plans.filter((plan) => plan.plan_key !== PlanKey.Free)
      : plans;

    return [...filteredPlans].sort((a, b) => {
      // Sort by monthly price (ascending) using selected currency
      const aPrice = getMonthlyPriceForPlanAndCurrency(a, currency);
      const bPrice = getMonthlyPriceForPlanAndCurrency(b, currency);

      // Handle NaN values - put plans with missing prices at the end
      if (Number.isNaN(aPrice) && Number.isNaN(bPrice)) return 0;
      if (Number.isNaN(aPrice)) return 1;
      if (Number.isNaN(bPrice)) return -1;

      return aPrice - bPrice;
    });
  }, [plans, selectedCurrency, currentSubscription?.is_active]);

  const synchronizeDescriptionHeights = () => {
    // Find all description elements by data attribute
    const descriptions = document.querySelectorAll(
      '[data-description]'
    ) as NodeListOf<HTMLElement>;
    if (descriptions.length === 0) return;

    // Reset heights
    descriptions.forEach((desc: HTMLElement) => {
      desc.style.minHeight = 'auto';
      desc.style.height = 'auto';
    });

    // Find max height
    const maxHeight = Math.max(
      ...Array.from(descriptions).map((desc: HTMLElement) => desc.scrollHeight)
    );

    // Apply max height
    descriptions.forEach((desc: HTMLElement) => {
      desc.style.minHeight = `${maxHeight}px`;
    });
  };

  // Use ResizeObserver to watch for changes
  const containerRef = useRef<HTMLDivElement>(null);
  useResizeObserver({
    ref: containerRef as React.RefObject<HTMLDivElement>,
    onResize: () => {
      // Small delay to ensure rendering is complete
      requestAnimationFrame(() => {
        synchronizeDescriptionHeights();
      });
    },
  });

  // Trigger synchronization when data changes
  useEffect(() => {
    const timer = setTimeout(() => {
      synchronizeDescriptionHeights();
    }, 10);

    return () => clearTimeout(timer);
  }, [sortedPlans, usagePlanDescriptions, period]);

  const getFeatureDescriptions = (plan: UsagePlanSchema) => {
    let dynamicFeatures =
      usagePlanDescriptions[plan.plan_key]?.feature_descriptions || [];

    if (!dynamicFeatures.length) {
      const features = plan.features.split('\n') || [];
      dynamicFeatures = features.map((feature: string) => ({
        text: feature,
        type: 'plus',
      }));
    }

    return dynamicFeatures;
  };

  const handlePeriodChange = (value: string) => {
    const newPeriod = value as SubscriptionPeriod;
    logWebUserEvent({
      actionName: 'SubscriptionPeriodTabClicked',
      context: {
        period: newPeriod,
        pageUrl: window.location.pathname,
      },
      componentContext: '',
    });
    setPeriod(newPeriod);
  };

  const handleSetPeriodAnnual = () => {
    logWebUserEvent({
      actionName: 'SaveByPayingAnnuallyLinkClicked',
      context: {
        pageUrl: window.location.pathname,
      },
    });
    setPeriod(ANNUAL);
  };

  // Dynamically pick the number of columns so we don't leave empty
  // cells on large screens. Tailwind needs *static* class names, so
  // we pre-enumerate the possibilities with clsx.
  const gridClassName = twMerge(
    'w-full gap-6 grid grid-cols-1 auto-rows-[1fr] items-start',
    sortedPlans.length >= 2 && 'min-[600px]:grid-cols-2',
    sortedPlans.length >= 3 && 'min-[1024px]:grid-cols-3',
    sortedPlans.length >= 4 && 'min-[1200px]:grid-cols-4'
  );

  // Check if any plan has an active discount for annual period
  const hasAnnualDiscount = useMemo(() => {
    if (!eligibleDiscountsResult?.eligible_discounts) return false;

    return Object.values(eligibleDiscountsResult.eligible_discounts).some(
      (planDiscounts) => {
        const annualDiscount = planDiscounts[ANNUAL];
        return annualDiscount?.percent_off || annualDiscount?.amount_off;
      }
    );
  }, [eligibleDiscountsResult?.eligible_discounts]);

  const saleBadge = hasAnnualDiscount
    ? {
        text: 'LIMITED TIME OFFER',
        className: 'bg-accent-brand text-foreground-primary-glass',
      }
    : {
        text: 'SAVE 20%',
        className: 'bg-accent-brand text-foreground-primary-glass',
      };

  return (
    <div className='mt-4 flex w-full flex-col items-center gap-10'>
      <RadioGroupWithBadges
        value={period}
        options={[
          { label: 'Monthly', value: MONTHLY },
          {
            label: 'Yearly',
            value: ANNUAL,
            badge: saleBadge,
          },
        ]}
        onChange={handlePeriodChange}
      />

      <div ref={containerRef} className={gridClassName}>
        {sortedPlans?.map((plan: UsagePlanSchema) => (
          <AuraSubscriptionCard
            key={plan.id}
            plan={plan}
            price={getPriceForPlan(plan, period)}
            priceBeforeDiscount={getMonthlyPriceForPlanAndCurrency(
              plan,
              selectedCurrency
            )}
            discountDetails={
              eligibleDiscountsResult?.eligible_discounts[plan.plan_key]?.[
                period
              ]
            }
            period={period}
            billed={period === ANNUAL ? 'yearly' : 'monthly'}
            features={getFeatureDescriptions(plan)}
            currentSubscription={currentSubscription}
            setPeriodAnnual={handleSetPeriodAnnual}
            planDescription={usagePlanDescriptions[plan.plan_key]}
            ctaButtons={ctaButtons}
            checkoutSource={checkoutSource}
            selectedCurrency={selectedCurrency}
          />
        ))}
      </div>
    </div>
  );
};
