/**
 * Currency utilities — single source of truth for formatting money in WooNooW.
 *
 * Goals:
 * - Prefer WooCommerce symbol when available (e.g., "Rp", "$", "RM").
 * - Fall back to ISO currency code using Intl if no symbol given.
 * - Reasonable default decimals (0 for common zero‑decimal currencies like IDR/JPY/KRW/VND).
 * - Allow overrides per call (locale/decimals/symbol usage).
 */

export type MoneyInput = number | string | null | undefined;

export type MoneyOptions = {
  /** ISO code like 'IDR', 'USD', 'MYR' */
  currency?: string;
  /** Symbol like 'Rp', '$', 'RM' */
  symbol?: string | null;
  /** Force number of fraction digits (Woo setting); if omitted, use heuristic or store */
  decimals?: number;
  /** Locale passed to Intl; if omitted, browser default */
  locale?: string;
  /** When true (default), use symbol if provided; otherwise always use Intl currency code */
  preferSymbol?: boolean;
  /** Woo thousand separator (e.g., '.' for IDR) */
  thousandSep?: string;
  /** Woo decimal separator (e.g., ',' for IDR) */
  decimalSep?: string;
  /** Woo currency position: 'left' | 'right' | 'left_space' | 'right_space' */
  position?: 'left' | 'right' | 'left_space' | 'right_space';
};

/**
 * Known zero‑decimal currencies across common stores.
 * (WooCommerce may also set decimals=0 per store; pass `decimals` to override.)
 */
export const ZERO_DECIMAL_CURRENCIES = new Set([
  'BIF','CLP','DJF','GNF','ISK','JPY','KMF','KRW','PYG','RWF','UGX','VND','VUV','XAF','XOF','XPF',
  // widely used as 0‑decimal in Woo stores
  'IDR','MYR'
]);

/** Resolve desired decimals. */
export function resolveDecimals(currency?: string, override?: number): number {
  if (typeof override === 'number' && override >= 0) return override;
  if (!currency) return 0;
  return ZERO_DECIMAL_CURRENCIES.has(currency.toUpperCase()) ? 0 : 2;
}

/** Resolve the best display token (symbol over code). */
export function resolveDisplayToken(opts: MoneyOptions): string | undefined {
  const token = (opts.preferSymbol ?? true) ? (opts.symbol || undefined) : undefined;
  return token || opts.currency;
}

function formatWithSeparators(num: number, decimals: number, thousandSep: string, decimalSep: string) {
  const fixed = (decimals >= 0 ? num.toFixed(decimals) : String(num));
  const [intRaw, frac = ''] = fixed.split('.');
  const intPart = intRaw.replace(/\B(?=(\d{3})+(?!\d))/g, thousandSep);
  return decimals > 0 ? `${intPart}${decimalSep}${frac}` : intPart;
}

export function formatMoney(value: MoneyInput, opts: MoneyOptions = {}): string {
  if (value === null || value === undefined || value === '') return '—';
  const num = typeof value === 'string' ? Number(value) : value;
  if (!isFinite(num as number)) return '—';

  const store = getStoreCurrency();
  const currency = opts.currency || store.currency || 'USD';
  const decimals = resolveDecimals(currency, opts.decimals ?? (typeof store.decimals === 'number' ? store.decimals : Number(store.decimals)));
  const thousandSep = opts.thousandSep ?? store.thousand_sep ?? ',';
  const decimalSep  = opts.decimalSep  ?? store.decimal_sep  ?? '.';
  const position = (opts.position ?? (store as any).position ?? (store as any).currency_pos ?? 'left') as 'left' | 'right' | 'left_space' | 'right_space';
  const symbol = (opts.symbol ?? store.symbol) as string | undefined;
  const preferSymbol = opts.preferSymbol !== false;

  if (preferSymbol && symbol) {
    const n = formatWithSeparators(num as number, decimals, thousandSep, decimalSep);
    switch (position) {
      case 'left': return `${symbol}${n}`;
      case 'left_space': return `${symbol} ${n}`;
      case 'right': return `${n}${symbol}`;
      case 'right_space': return `${n} ${symbol}`;
      default: return `${symbol}${n}`;
    }
  }

  try {
    return new Intl.NumberFormat(opts.locale, {
      style: 'currency',
      currency,
      minimumFractionDigits: decimals,
      maximumFractionDigits: decimals,
    }).format(num as number);
  } catch {
    const n = formatWithSeparators(num as number, decimals, thousandSep, decimalSep);
    return `${currency} ${n}`;
  }
}

export const formatPrice = formatMoney;

export function makeMoneyFormatter(opts: MoneyOptions) {
  const store = getStoreCurrency();
  const currency = opts.currency || store.currency || 'USD';
  const decimals = resolveDecimals(currency, opts.decimals ?? (typeof store.decimals === 'number' ? store.decimals : Number(store.decimals)));
  const thousandSep = opts.thousandSep ?? store.thousand_sep ?? ',';
  const decimalSep  = opts.decimalSep  ?? store.decimal_sep  ?? '.';
  const position = (opts.position ?? (store as any).position ?? (store as any).currency_pos ?? 'left') as 'left' | 'right' | 'left_space' | 'right_space';
  const symbol = (opts.symbol ?? store.symbol) as string | undefined;
  const preferSymbol = opts.preferSymbol !== false && !!symbol;

  if (preferSymbol) {
    return (v: MoneyInput) => {
      if (v === null || v === undefined || v === '') return '—';
      const num = typeof v === 'string' ? Number(v) : v;
      if (!isFinite(num as number)) return '—';
      const n = formatWithSeparators(num as number, decimals, thousandSep, decimalSep);
      switch (position) {
        case 'left': return `${symbol}${n}`;
        case 'left_space': return `${symbol} ${n}`;
        case 'right': return `${n}${symbol}`;
        case 'right_space': return `${n} ${symbol}`;
        default: return `${symbol}${n}`;
      }
    };
  }

  let intl: Intl.NumberFormat | null = null;
  try {
    intl = new Intl.NumberFormat(opts.locale, {
      style: 'currency',
      currency,
      minimumFractionDigits: decimals,
      maximumFractionDigits: decimals,
    });
  } catch {
    intl = null;
  }

  return (v: MoneyInput) => {
    if (v === null || v === undefined || v === '') return '—';
    const num = typeof v === 'string' ? Number(v) : v;
    if (!isFinite(num as number)) return '—';
    if (intl) return intl.format(num as number);
    const n = formatWithSeparators(num as number, decimals, thousandSep, decimalSep);
    return `${currency} ${n}`;
  };
}

/**
 * Convenience hook wrapper for React components (optional import).
 * Use inside components to avoid repeating memo logic.
 */
export function useMoneyFormatter(opts: MoneyOptions) {
  // Note: file lives in /lib so we keep dependency-free; simple memo by JSON key is fine.
  const key = JSON.stringify({
    c: opts.currency,
    s: opts.symbol,
    d: resolveDecimals(opts.currency, opts.decimals),
    l: opts.locale,
    p: opts.preferSymbol !== false,
    ts: opts.thousandSep,
    ds: opts.decimalSep,
    pos: opts.position,
  });
  const ref = (globalThis as any).__wnw_money_cache || ((globalThis as any).__wnw_money_cache = new Map());
  if (!ref.has(key)) ref.set(key, makeMoneyFormatter(opts));
  return ref.get(key) as (v: MoneyInput) => string;
}
/**
 * Read global WooCommerce store currency data provided via window.WNW_STORE.
 * Returns normalized currency, symbol, and decimals for consistent usage.
 */
export function getStoreCurrency() {
  const store = (window as any).WNW_STORE || (window as any).WNW_META || {};
  const decimals = typeof store.decimals === 'number' ? store.decimals : Number(store.decimals);
  const position = (store.currency_pos || store.currency_position || 'left') as 'left' | 'right' | 'left_space' | 'right_space';
  
  const result = {
    currency: store.currency || 'USD',
    symbol: store.currency_symbol || '$',
    decimals: Number.isFinite(decimals) ? decimals : 2,
    thousand_sep: store.thousand_sep || ',',
    decimal_sep: store.decimal_sep || '.',
    position,
  };
  
  // Debug log in dev mode
  if ((window as any).wnw?.isDev && !((window as any).__wnw_currency_logged)) {
    (window as any).__wnw_currency_logged = true;
  }
  
  return result;
}