/**
 * Pricing Helper Functions
 * Currency conversion and prorated charge calculations
 */

import type { Currency, PricingTier } from '@/lib/types/pricing';
import { PRICING_TIERS } from '@/lib/config/pricing-tiers';
import type { TierId, BillingPeriod } from '@/lib/types/plan-change.types';

// Currency conversion rates (GBP as base) - Updated regularly
export const CURRENCY_RATES: Record<Currency, number> = {
  GBP: 1,
  USD: 1.27,
  EUR: 1.17,
  SAR: 4.76,
  AED: 4.66,
  QAR: 4.62,
  KWD: 0.39,
  BHD: 0.48,
  OMR: 0.49,
};

/**
 * Convert GBP price to target currency
 */
export function convertPrice(gbpPrice: number, targetCurrency: Currency): number {
  return Math.round(gbpPrice * CURRENCY_RATES[targetCurrency]);
}

/**
 * Calculate prorated upgrade cost
 * @param currentMonthlyPrice - Current tier monthly price
 * @param newMonthlyPrice - New tier monthly price
 * @param daysRemaining - Days until next billing date
 * @param billingPeriod - monthly or yearly
 * @returns Prorated amount to charge
 */
export function calculateProratedUpgrade(
  currentMonthlyPrice: number,
  newMonthlyPrice: number,
  daysRemaining: number,
  billingPeriod: 'monthly' | 'yearly' = 'monthly'
): number {
  const periodDays = billingPeriod === 'monthly' ? 30 : 365;

  // Calculate daily rates
  const currentDailyRate = currentMonthlyPrice / periodDays;
  const newDailyRate = newMonthlyPrice / periodDays;

  // Calculate unused credit from current plan
  const unusedCredit = currentDailyRate * daysRemaining;

  // Calculate cost for new plan for remaining days
  const newPlanCost = newDailyRate * daysRemaining;

  // Prorated charge = new plan cost - unused credit
  const proratedCharge = newPlanCost - unusedCredit;

  return Math.max(0, Math.round(proratedCharge * 100) / 100);
}

/**
 * Calculate days remaining until billing date using UTC
 * Uses UTC to ensure consistent calculation across timezones
 */
export function getDaysUntilBilling(currentPeriodEnd: Date): number {
  const now = new Date();
  const nowUTC = Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate());

  const end = new Date(currentPeriodEnd);
  const endUTC = Date.UTC(end.getUTCFullYear(), end.getUTCMonth(), end.getUTCDate());

  const diffTime = endUTC - nowUTC;
  const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
  return Math.max(0, diffDays);
}

// Alias for backward compatibility
export const getDaysRemaining = getDaysUntilBilling;

/**
 * Calculate credit from downgrade
 * @param currentMonthlyPrice - Current tier monthly price
 * @param newMonthlyPrice - New tier monthly price (lower than current)
 * @param daysRemaining - Days until next billing date
 * @param billingPeriod - monthly or yearly
 * @returns Credit details including amount and next billing charge
 */
export function calculateDowngradeCredit(
  currentMonthlyPrice: number,
  newMonthlyPrice: number,
  daysRemaining: number,
  billingPeriod: 'monthly' | 'yearly' = 'monthly'
): {
  creditAmount: number;
  nextBillingCharge: number;
  creditApplied: number;
} {
  const periodDays = billingPeriod === 'monthly' ? 30 : 365;

  // Calculate daily rates
  const currentDailyRate = currentMonthlyPrice / periodDays;
  const newDailyRate = newMonthlyPrice / periodDays;

  // Calculate unused credit from current plan
  const unusedCredit = currentDailyRate * daysRemaining;

  // Calculate cost for new plan for remaining days
  const newPlanCost = newDailyRate * daysRemaining;

  // Excess credit (positive for downgrades)
  const excessCredit = unusedCredit - newPlanCost;

  // Apply credit to next month's bill
  const nextMonthPrice = newMonthlyPrice;
  const creditToApply = Math.min(excessCredit, nextMonthPrice);
  const nextBillingCharge = Math.max(0, nextMonthPrice - creditToApply);

  return {
    creditAmount: Math.round(excessCredit * 100) / 100,
    nextBillingCharge: Math.round(nextBillingCharge * 100) / 100,
    creditApplied: Math.round(creditToApply * 100) / 100
  };
}

/**
 * Check if setup fee should be charged for a plan change
 * @param setupFeePaid - Whether setup fee has already been paid
 * @param newTier - The tier being upgraded/downgraded to
 * @returns true if setup fee should be charged
 */
export function shouldChargeSetupFee(
  setupFeePaid: boolean,
  newTier: PricingTier
): boolean {
  // NEVER charge setup fee again if already paid
  if (setupFeePaid) {
    return false;
  }

  // Only charge if new tier has setup fee and it hasn't been paid
  return (newTier.setupGBP || 0) > 0;
}

/**
 * Get setup fee amount for new tier in target currency
 * @param newTier - The tier to get setup fee for
 * @param currency - Target currency
 * @returns Setup fee amount in target currency
 */
export function getSetupFeeAmount(
  newTier: PricingTier,
  currency: Currency
): number {
  const setupGBP = newTier.setupGBP || 0;
  return convertPrice(setupGBP, currency);
}

/**
 * Detect user's currency based on country
 */
export function getCurrencyFromCountry(country?: string): Currency {
  const countryMap: Record<string, Currency> = {
    'qatar': 'QAR',
    'qa': 'QAR',
    'saudi arabia': 'SAR',
    'sa': 'SAR',
    'uae': 'AED',
    'united arab emirates': 'AED',
    'ae': 'AED',
    'kuwait': 'KWD',
    'kw': 'KWD',
    'bahrain': 'BHD',
    'bh': 'BHD',
    'oman': 'OMR',
    'om': 'OMR',
    'uk': 'GBP',
    'united kingdom': 'GBP',
    'gb': 'GBP',
    'us': 'USD',
    'united states': 'USD',
    'usa': 'USD',
  };

  const normalized = country?.toLowerCase() || '';
  return countryMap[normalized] || 'QAR'; // Default to QAR for GCC
}

/**
 * Yearly discount constant (7%)
 * This MUST match PRICING_CONFIG.YEARLY_DISCOUNT_PERCENT
 */
export const YEARLY_DISCOUNT_PERCENT = 7;
export const YEARLY_DISCOUNT_MULTIPLIER = 1 - (YEARLY_DISCOUNT_PERCENT / 100); // 0.93

/**
 * Calculate yearly total with 7% discount
 * Formula: monthly_price × 12 months × 0.93 (7% discount)
 *
 * @param monthlyPrice - Monthly price (in any unit - cents or dollars)
 * @returns Yearly total with 7% discount applied
 */
export function calculateYearlyTotal(monthlyPrice: number): number {
  return Math.round(monthlyPrice * 12 * YEARLY_DISCOUNT_MULTIPLIER * 100) / 100;
}

/**
 * Calculate yearly total in cents (for Stripe)
 * Formula: monthly_price_cents × 12 × 0.93
 *
 * @param monthlyPriceCents - Monthly price in cents
 * @returns Yearly total in cents with 7% discount
 */
export function calculateYearlyTotalCents(monthlyPriceCents: number): number {
  return Math.round(monthlyPriceCents * 12 * YEARLY_DISCOUNT_MULTIPLIER);
}

/**
 * Calculate monthly equivalent from yearly total
 * This is the discounted monthly price shown on pricing pages
 *
 * @param monthlyPrice - Original monthly price
 * @returns Discounted monthly equivalent (monthly × 0.93)
 */
export function calculateMonthlyEquivalent(monthlyPrice: number): number {
  return Math.round(monthlyPrice * YEARLY_DISCOUNT_MULTIPLIER * 100) / 100;
}

/**
 * Get price for a tier in QAR (smallest unit - fils)
 * @param tierId - Tier identifier (tier1-tier5)
 * @param billingPeriod - monthly or yearly
 * @returns Price in fils (QAR smallest unit, 100 fils = 1 QAR)
 */
export function getTierPriceQAR(tierId: TierId, billingPeriod: BillingPeriod): number {
  const tier = PRICING_TIERS.find((t) => t.id === tierId);
  if (!tier) return 0;

  const monthlyQAR = tier.priceGBP * CURRENCY_RATES.QAR;

  if (billingPeriod === 'yearly') {
    return Math.round(calculateYearlyTotal(monthlyQAR) * 100);
  }

  return Math.round(monthlyQAR * 100);
}

/**
 * Get price in QAR for display (whole QAR, not fils)
 * @param tierId - Tier identifier (tier1-tier5)
 * @param billingPeriod - monthly or yearly
 * @returns Price in whole QAR units
 */
export function getTierPriceQARDisplay(tierId: TierId, billingPeriod: BillingPeriod): number {
  return Math.round(getTierPriceQAR(tierId, billingPeriod) / 100);
}
