'use client';

import clsx from 'clsx';
import { useEffect, useRef, useState } from 'react';
import { twMerge } from 'tailwind-merge';

import {
  CURRENCY_TO_LOCALE_MAP,
  Currency,
  ZERO_DECIMAL_CURRENCIES,
} from '@/app/(root)/account/constants';
import Button, {
  ButtonShape,
  ButtonSize,
  ButtonVariant,
} from '@/components/button/Button';
import { useCurrencyOptions } from '@/hooks/useCurrencyOptions';
import { CaretDownIcon, CaretUpIcon } from '@/icons';
import { components } from '@/lib/gen';
import { PlanKey } from '@/state/sessionStore';
import { SubscriptionPeriod } from '@/utils/session';

interface CurrencySelectorProps {
  value: Currency;
  onChange: (currency: Currency) => void;
  supportedCurrencies?: Currency[];
  className?: string;
}

export const CurrencySelector: React.FC<CurrencySelectorProps> = ({
  value,
  onChange,
  supportedCurrencies,
  className,
}) => {
  const [isOpen, setIsOpen] = useState(false);
  const dropdownRef = useRef<HTMLDivElement>(null);
  const currencyOptions = useCurrencyOptions();

  // Filter options to only include supported currencies
  const availableOptions = supportedCurrencies
    ? currencyOptions.filter((option) =>
        supportedCurrencies.includes(option.value)
      )
    : currencyOptions;

  const selectedOption = availableOptions.find(
    (option) => option.value === value
  );

  useEffect(() => {
    const handleClickOutside = (event: MouseEvent) => {
      if (
        dropdownRef.current &&
        !dropdownRef.current.contains(event.target as Node)
      ) {
        setIsOpen(false);
      }
    };

    if (isOpen) {
      document.addEventListener('mousedown', handleClickOutside);
      return () => {
        document.removeEventListener('mousedown', handleClickOutside);
      };
    }
  }, [isOpen]);

  const handleToggle = () => {
    setIsOpen(!isOpen);
  };

  const handleOptionSelect = (currency: Currency) => {
    onChange(currency);
    setIsOpen(false);
  };

  return (
    <div className={twMerge('relative font-sans', className)} ref={dropdownRef}>
      <Button
        onClick={handleToggle}
        variant={ButtonVariant.LightGlass}
        size={ButtonSize.Small}
        shape={ButtonShape.Pill}
        aria-expanded={isOpen}
        aria-haspopup='listbox'
        aria-label='Select currency'
        iconStart={selectedOption?.icon}
        iconEnd={isOpen ? CaretUpIcon : CaretDownIcon}
        iconClassName='w-5 h-5'
      >
        {selectedOption?.label}
      </Button>

      {isOpen && (
        <div
          role='listbox'
          className={clsx(
            'absolute top-full left-0 mt-1 w-full',
            'rounded-xl border border-white/20 bg-black/20 backdrop-blur-lg',
            'z-50 shadow-lg',
            'overflow-hidden',
            'flex flex-col'
          )}
        >
          {availableOptions.map((option, index) => (
            <Button
              key={option.value}
              onClick={() => handleOptionSelect(option.value)}
              variant={ButtonVariant.LightGlass}
              size={ButtonSize.Small}
              active={value === option.value}
              iconStart={option.icon}
              className={clsx(
                'w-full',
                index === 0 && 'rounded-t-xl rounded-b-none',
                index === availableOptions.length - 1 &&
                  'rounded-t-none rounded-b-xl',
                index !== 0 &&
                  index !== availableOptions.length - 1 &&
                  'rounded-none'
              )}
              contentClassName='justify-start'
              iconClassName='w-5 h-5'
            >
              {option.label}
            </Button>
          ))}
        </div>
      )}
    </div>
  );
};

/**
 * Formats a price for display, rounding to 2 decimal places but showing integers without decimals
 * Returns "N/A" for NaN values (when price is not available)
 */
export const getDisplayPrice = (
  price: number,
  currency: Currency,
  forceDecimals = false
): string => {
  if (Number.isNaN(price)) {
    return 'N/A';
  }
  const isZeroDecimalCurrency = ZERO_DECIMAL_CURRENCIES.includes(currency);
  const effectiveLocale = CURRENCY_TO_LOCALE_MAP[currency];

  // If forceDecimals is true and it's not a zero decimal currency, always show 2 decimals
  const shouldForceDecimals = forceDecimals && !isZeroDecimalCurrency;

  return price.toLocaleString(effectiveLocale, {
    style: 'currency',
    currency,
    minimumFractionDigits: shouldForceDecimals
      ? 2
      : isZeroDecimalCurrency || Number.isInteger(price)
        ? 0
        : 2,
    maximumFractionDigits: isZeroDecimalCurrency ? 0 : 2,
    trailingZeroDisplay: shouldForceDecimals ? 'auto' : 'stripIfInteger',
  });
};

/**
 * Convert percent_off to decimal multiplier, handling special case for 33% -> 0.3333
 * This matches Stripe's internal handling where 33% is actually 0.3333 (33.33%)
 */
export const getDiscountMultiplier = (percentOff: number): number => {
  if (percentOff === 33) {
    return 0.3333;
  }
  return percentOff / 100;
};

export const getSaleDisplayPrice = (
  price: number,
  currency: Currency,
  percentOff: number,
  forceDecimals = false
): string => {
  if (Number.isNaN(price) || Number.isNaN(percentOff)) {
    return 'N/A';
  }

  const discountMultiplier = getDiscountMultiplier(percentOff);
  const salePrice = price * (1 - discountMultiplier);
  return getDisplayPrice(salePrice, currency, forceDecimals);
};

// Use the generated PriceSchema type from the API
type PriceSchema = components['schemas']['PriceSchema'];

// Type for UsagePlanSchema with prices array - extends the generated type
type UsagePlanWithPrices = components['schemas']['UsagePlanSchema'];

// Utility functions for working with the new pricing structure
export const getPriceForPlanAndCurrency = (
  plan: UsagePlanWithPrices,
  currency: Currency,
  period: SubscriptionPeriod
): number => {
  if (plan.plan_key === PlanKey.Free) {
    return 0;
  }

  // Look for the price in the requested currency first
  if (plan.prices && Array.isArray(plan.prices)) {
    const price = plan.prices.find(
      (p: PriceSchema) => p.currency === currency && p.period_type === period
    );

    if (price) {
      return price.price;
    }
  }

  // No price found for the requested currency and period
  // Return NaN to force "N/A" display when requested currency is unavailable
  // This prevents showing USD prices with non-USD currency symbols
  return NaN;
};

export const getMonthlyPriceForPlanAndCurrency = (
  plan: UsagePlanWithPrices,
  currency: Currency
): number => {
  return getPriceForPlanAndCurrency(plan, currency, SubscriptionPeriod.Monthly);
};

export const getAnnualPriceForPlanAndCurrency = (
  plan: UsagePlanWithPrices,
  currency: Currency
): number => {
  return getPriceForPlanAndCurrency(plan, currency, SubscriptionPeriod.Annual);
};

export default CurrencySelector;
