"use client";

import { useMemo } from "react";
import { create } from "zustand";
import { formatCurrency } from "@/lib/money";

/**
 * Currency Configuration
 *
 * Display metadata for the currencies the admin can pick as the store default.
 * The store-wide currency is admin-controlled only (settings.general
 * .defaultCurrency) — customers cannot choose a display currency, so there is
 * no client-side persistence and no conversion: prices are stored and shown in
 * the store currency as-is.
 */
export interface Currency {
  code: string;
  symbol: string;
  name: string;
  locale: string;
}

export const CURRENCIES: Currency[] = [
  {
    code: "USD",
    symbol: "$",
    name: "US Dollar",
    locale: "en-US",
  },
  {
    code: "EUR",
    symbol: "€",
    name: "Euro",
    locale: "de-DE",
  },
  {
    code: "GBP",
    symbol: "£",
    name: "British Pound",
    locale: "en-GB",
  },
  {
    code: "BDT",
    symbol: "৳",
    name: "Bangladeshi Taka",
    locale: "bn-BD",
  },
  {
    code: "INR",
    symbol: "₹",
    name: "Indian Rupee",
    locale: "en-IN",
  },
  {
    code: "TRY",
    symbol: "₺",
    name: "Turkish Lira",
    locale: "tr-TR",
  },
  {
    code: "PKR",
    symbol: "₨",
    name: "Pakistani Rupee",
    locale: "ur-PK",
  },
  {
    code: "JPY",
    symbol: "¥",
    name: "Japanese Yen",
    locale: "ja-JP",
  },
  {
    code: "CNY",
    symbol: "¥",
    name: "Chinese Yuan",
    locale: "zh-CN",
  },
  {
    code: "AUD",
    symbol: "A$",
    name: "Australian Dollar",
    locale: "en-AU",
  },
  {
    code: "CAD",
    symbol: "C$",
    name: "Canadian Dollar",
    locale: "en-CA",
  },
  {
    code: "PEN",
    symbol: "S/",
    name: "Peruvian Sol",
    locale: "es-PE",
  },
  {
    code: "SAR",
    symbol: "﷼",
    name: "Saudi Riyal",
    locale: "ar-SA",
  },
  {
    code: "AED",
    symbol: "د.إ",
    name: "UAE Dirham",
    locale: "ar-AE",
  },
  {
    code: "SGD",
    symbol: "S$",
    name: "Singapore Dollar",
    locale: "en-SG",
  },
  {
    code: "MYR",
    symbol: "RM",
    name: "Malaysian Ringgit",
    locale: "ms-MY",
  },
  {
    code: "THB",
    symbol: "฿",
    name: "Thai Baht",
    locale: "th-TH",
  },
  {
    code: "KRW",
    symbol: "₩",
    name: "South Korean Won",
    locale: "ko-KR",
  },
  {
    code: "ZAR",
    symbol: "R",
    name: "South African Rand",
    locale: "en-ZA",
  },
  {
    code: "KES",
    symbol: "KSh",
    name: "Kenyan Shilling",
    locale: "en-KE",
  },
  {
    code: "UGX",
    symbol: "USh",
    name: "Ugandan Shilling",
    locale: "en-UG",
  },
  {
    code: "NGN",
    symbol: "₦",
    name: "Nigerian Naira",
    locale: "en-NG",
  },
  {
    code: "DZD",
    symbol: "د.ج",
    name: "Algerian Dinar",
    locale: "ar-DZ",
  },
  {
    code: "QAR",
    symbol: "ر.ق",
    name: "Qatari Riyal",
    locale: "ar-QA",
  },
  {
    code: "KWD",
    symbol: "د.ك",
    name: "Kuwaiti Dinar",
    locale: "ar-KW",
  },
  {
    code: "BHD",
    symbol: ".د.ب",
    name: "Bahraini Dinar",
    locale: "ar-BH",
  },
  {
    code: "OMR",
    symbol: "ر.ع.",
    name: "Omani Rial",
    locale: "ar-OM",
  },
];

// ISO 4217 minor-unit exceptions among the supported currencies.
const ZERO_DECIMAL_CURRENCY_CODES = new Set(["JPY", "KRW", "UGX"]);
const THREE_DECIMAL_CURRENCY_CODES = new Set(["KWD", "BHD", "OMR"]);

function resolveCurrency(code: string): Currency {
  const normalized = String(code || "").toUpperCase();
  return (
    CURRENCIES.find((c) => c.code === normalized) || {
      code: normalized || "USD",
      symbol: normalized || "USD",
      name: normalized || "USD",
      locale: "en-US",
    }
  );
}

interface CurrencyState {
  currency: Currency;
  setCurrency: (code: string) => void;
  formatPrice: (price: number) => string;
}

/**
 * Currency Store with Zustand
 *
 * Mirrors the admin-configured default currency. Written only by
 * <CurrencyApplier> (on load / settings refresh) and the admin settings save
 * flow — never by customer-facing UI. Not persisted: the authoritative value
 * comes from the server on every load, so caching a copy in localStorage can
 * only ever serve a stale currency.
 */
export const useCurrencyStore = create<CurrencyState>()((set, get) => ({
  currency: CURRENCIES[0],

  setCurrency: (code: string) => {
    const currency = resolveCurrency(code);
    set((state) =>
      state.currency.code === currency.code ? state : { currency },
    );
  },

  formatPrice: (price: number) => {
    const { currency } = get();
    const fractionDigits = fractionDigitsFor(currency.code);
    return formatCurrency(price, currency.code, currency.locale, {
      minimumFractionDigits: fractionDigits,
      maximumFractionDigits: fractionDigits,
    });
  },
}));

/**
 * Hook to access the store currency and price formatter.
 *
 * Subscribes to the whole store so consumers that only destructure
 * `formatPrice` still re-render when the currency changes.
 */
export function useCurrency() {
  const { currency, setCurrency, formatPrice } = useCurrencyStore();

  return {
    currency,
    currencies: CURRENCIES,
    setCurrency,
    formatPrice,
  };
}

function fractionDigitsFor(code: string) {
  if (ZERO_DECIMAL_CURRENCY_CODES.has(code)) return 0;
  if (THREE_DECIMAL_CURRENCY_CODES.has(code)) return 3;
  return 2;
}

/**
 * Price formatter pinned to an explicit currency code.
 *
 * Orders freeze the currency they were charged in (`order.currency`), so a
 * historical order must be formatted with THAT code — formatting it with the
 * store's current default silently relabels every past order's totals the
 * moment an admin switches the store currency. Falls back to the store
 * formatter when no code is given (legacy rows written before the field).
 */
export function useCurrencyFormatter(currencyCode?: string | null) {
  const { formatPrice } = useCurrency();

  return useMemo(() => {
    const normalized = String(currencyCode || "").toUpperCase();
    if (!normalized) return formatPrice;

    const currency = resolveCurrency(normalized);
    const fractionDigits = fractionDigitsFor(currency.code);
    return (price: number) =>
      formatCurrency(price, currency.code, currency.locale, {
        minimumFractionDigits: fractionDigits,
        maximumFractionDigits: fractionDigits,
      });
  }, [currencyCode, formatPrice]);
}
