// Currency catalog + format helpers for Invoice generator
const CURRENCIES = [
  { code: 'USD', symbol: '$',   name: 'US Dollar',           flag: '🇺🇸' },
  { code: 'EUR', symbol: '€',   name: 'Euro',                flag: '🇪🇺' },
  { code: 'GBP', symbol: '£',   name: 'British Pound',       flag: '🇬🇧' },
  { code: 'JPY', symbol: '¥',   name: 'Japanese Yen',        flag: '🇯🇵' },
  { code: 'CNY', symbol: '¥',   name: 'Chinese Yuan',        flag: '🇨🇳' },
  { code: 'CAD', symbol: 'CA$', name: 'Canadian Dollar',     flag: '🇨🇦' },
  { code: 'AUD', symbol: 'A$',  name: 'Australian Dollar',   flag: '🇦🇺' },
  { code: 'NZD', symbol: 'NZ$', name: 'New Zealand Dollar',  flag: '🇳🇿' },
  { code: 'CHF', symbol: 'Fr',  name: 'Swiss Franc',         flag: '🇨🇭' },
  { code: 'HKD', symbol: 'HK$', name: 'Hong Kong Dollar',    flag: '🇭🇰' },
  { code: 'SGD', symbol: 'S$',  name: 'Singapore Dollar',    flag: '🇸🇬' },
  { code: 'KRW', symbol: '₩',   name: 'South Korean Won',    flag: '🇰🇷' },
  { code: 'INR', symbol: '₹',   name: 'Indian Rupee',        flag: '🇮🇳' },
  { code: 'BRL', symbol: 'R$',  name: 'Brazilian Real',      flag: '🇧🇷' },
  { code: 'MXN', symbol: 'MX$', name: 'Mexican Peso',        flag: '🇲🇽' },
  { code: 'ZAR', symbol: 'R',   name: 'South African Rand',  flag: '🇿🇦' },
  { code: 'AED', symbol: 'د.إ', name: 'UAE Dirham',          flag: '🇦🇪' },
  { code: 'SAR', symbol: '﷼',   name: 'Saudi Riyal',         flag: '🇸🇦' },
  { code: 'ILS', symbol: '₪',   name: 'Israeli Shekel',      flag: '🇮🇱' },
  { code: 'TRY', symbol: '₺',   name: 'Turkish Lira',        flag: '🇹🇷' },
  { code: 'SEK', symbol: 'kr',  name: 'Swedish Krona',       flag: '🇸🇪' },
  { code: 'NOK', symbol: 'kr',  name: 'Norwegian Krone',     flag: '🇳🇴' },
  { code: 'DKK', symbol: 'kr',  name: 'Danish Krone',        flag: '🇩🇰' },
  { code: 'PLN', symbol: 'zł',  name: 'Polish Złoty',        flag: '🇵🇱' },
  { code: 'CZK', symbol: 'Kč',  name: 'Czech Koruna',        flag: '🇨🇿' },
  { code: 'HUF', symbol: 'Ft',  name: 'Hungarian Forint',    flag: '🇭🇺' },
  { code: 'RON', symbol: 'lei', name: 'Romanian Leu',        flag: '🇷🇴' },
  { code: 'UAH', symbol: '₴',   name: 'Ukrainian Hryvnia',   flag: '🇺🇦' },
  { code: 'RUB', symbol: '₽',   name: 'Russian Ruble',       flag: '🇷🇺' },
  { code: 'THB', symbol: '฿',   name: 'Thai Baht',           flag: '🇹🇭' },
  { code: 'PHP', symbol: '₱',   name: 'Philippine Peso',     flag: '🇵🇭' },
  { code: 'IDR', symbol: 'Rp',  name: 'Indonesian Rupiah',   flag: '🇮🇩' },
  { code: 'MYR', symbol: 'RM',  name: 'Malaysian Ringgit',   flag: '🇲🇾' },
  { code: 'VND', symbol: '₫',   name: 'Vietnamese Dong',     flag: '🇻🇳' },
  { code: 'ARS', symbol: 'AR$', name: 'Argentine Peso',      flag: '🇦🇷' },
  { code: 'CLP', symbol: 'CL$', name: 'Chilean Peso',        flag: '🇨🇱' },
  { code: 'COP', symbol: 'CO$', name: 'Colombian Peso',      flag: '🇨🇴' },
  { code: 'PEN', symbol: 'S/',  name: 'Peruvian Sol',        flag: '🇵🇪' },
  { code: 'EGP', symbol: 'E£',  name: 'Egyptian Pound',      flag: '🇪🇬' },
  { code: 'NGN', symbol: '₦',   name: 'Nigerian Naira',      flag: '🇳🇬' },
  { code: 'KES', symbol: 'KSh', name: 'Kenyan Shilling',     flag: '🇰🇪' },
  { code: 'PKR', symbol: '₨',   name: 'Pakistani Rupee',     flag: '🇵🇰' },
  { code: 'BDT', symbol: '৳',   name: 'Bangladeshi Taka',    flag: '🇧🇩' },
  { code: 'ISK', symbol: 'kr',  name: 'Icelandic Króna',     flag: '🇮🇸' },
  { code: 'CRC', symbol: '₡',   name: 'Costa Rican Colón',   flag: '🇨🇷' },
];
const CUR_MAP = Object.fromEntries(CURRENCIES.map(c => [c.code, c]));

// zero-decimal currencies (per ISO 4217)
const ZERO_DEC = new Set(['JPY','KRW','CLP','VND','IDR','HUF','ISK','TWD','CRC']);

function curInfo(code) { return CUR_MAP[code] || CURRENCIES[0]; }

function fmtMoney(n, code) {
  const v = Number(n) || 0;
  const c = curInfo(code);
  const digits = ZERO_DEC.has(c.code) ? 0 : 2;
  try {
    return new Intl.NumberFormat('en-US', {
      style: 'currency', currency: c.code,
      minimumFractionDigits: digits, maximumFractionDigits: digits,
    }).format(v);
  } catch {
    return `${c.symbol}${v.toFixed(digits)}`;
  }
}

function fmtNumber(n, currency) {
  const v = Number(n) || 0;
  const digits = ZERO_DEC.has(currency) ? 0 : 2;
  return v.toLocaleString('en-US', { minimumFractionDigits: digits, maximumFractionDigits: digits });
}

function parseNumber(str) {
  if (str === '' || str === null || str === undefined) return 0;
  const cleaned = String(str).replace(/[^0-9.\-]/g, '');
  const n = parseFloat(cleaned);
  return isNaN(n) ? 0 : n;
}

// Map of ISO 3166-1 region → currency code, restricted to currencies we
// actually carry in CURRENCIES. Any region not listed falls back to USD.
const REGION_TO_CCY = {
  US: 'USD', CA: 'CAD', MX: 'MXN', BR: 'BRL', AR: 'ARS', CL: 'CLP',
  CO: 'COP', PE: 'PEN', CR: 'CRC',
  GB: 'GBP',
  // SEPA / euro members
  IE: 'EUR', DE: 'EUR', FR: 'EUR', ES: 'EUR', IT: 'EUR', NL: 'EUR',
  BE: 'EUR', AT: 'EUR', PT: 'EUR', GR: 'EUR', FI: 'EUR', LU: 'EUR',
  SK: 'EUR', SI: 'EUR', CY: 'EUR', MT: 'EUR', EE: 'EUR', LV: 'EUR',
  LT: 'EUR', HR: 'EUR',
  CH: 'CHF', SE: 'SEK', NO: 'NOK', DK: 'DKK', IS: 'ISK',
  PL: 'PLN', CZ: 'CZK', HU: 'HUF', RO: 'RON', UA: 'UAH', RU: 'RUB',
  TR: 'TRY', IL: 'ILS', AE: 'AED', SA: 'SAR', EG: 'EGP',
  ZA: 'ZAR', NG: 'NGN', KE: 'KES',
  IN: 'INR', PK: 'PKR', BD: 'BDT',
  JP: 'JPY', CN: 'CNY', KR: 'KRW', HK: 'HKD', SG: 'SGD',
  TH: 'THB', PH: 'PHP', ID: 'IDR', MY: 'MYR', VN: 'VND',
  AU: 'AUD', NZ: 'NZD',
};

// Guess the user's currency from the browser locale (e.g. "en-GB" → GBP).
// Used as a synchronous fallback while IP detection (below) is in flight.
function detectCurrencyByLocale() {
  try {
    const langs = (navigator.languages && navigator.languages.length)
      ? navigator.languages
      : [navigator.language || 'en-US'];
    for (const lang of langs) {
      try {
        const region = new Intl.Locale(lang).maximize().region;
        if (region && REGION_TO_CCY[region] && CUR_MAP[REGION_TO_CCY[region]]) {
          return REGION_TO_CCY[region];
        }
      } catch {}
    }
  } catch {}
  return 'USD';
}

// Async IP-based detection via ipapi.co (free, no key, ~30k req/month).
// Returns a currency code we support, or null. The result is cached in
// localStorage so subsequent visits skip the network call.
const IP_CCY_CACHE_KEY = 'pp-ip-currency';
async function detectCurrencyByIP() {
  try {
    const r = await fetch('https://ipapi.co/json/', { cache: 'no-store' });
    if (!r.ok) return null;
    const j = await r.json();
    let ccy = null;
    if (j.currency && CUR_MAP[j.currency]) {
      ccy = j.currency;
    } else if (j.country_code && REGION_TO_CCY[j.country_code]) {
      ccy = REGION_TO_CCY[j.country_code];
    }
    if (ccy) {
      try { localStorage.setItem(IP_CCY_CACHE_KEY, ccy); } catch {}
    }
    return ccy;
  } catch {
    return null;
  }
}

// Synchronous initial seed: prefer the cached IP result from a previous
// visit; if none, fall back to the locale guess. The mount-time IP fetch
// in the App will overwrite this with the actual IP-derived currency.
function detectInitialCurrency() {
  try {
    const cached = localStorage.getItem(IP_CCY_CACHE_KEY);
    if (cached && CUR_MAP[cached]) return cached;
  } catch {}
  return detectCurrencyByLocale();
}

// Back-compat alias — existing callers (defaultInvoice etc.) use detectCurrency.
const detectCurrency = detectInitialCurrency;

// Today as YYYY-MM-DD
function todayISO() {
  const d = new Date();
  const mm = String(d.getMonth() + 1).padStart(2, '0');
  const dd = String(d.getDate()).padStart(2, '0');
  return `${d.getFullYear()}-${mm}-${dd}`;
}

// "May 24, 2026"  (US default)
function fmtDate(iso, locale) {
  if (!iso) return '';
  const d = new Date(iso + 'T00:00:00');
  if (isNaN(d)) return iso;
  if (locale === 'EU') {
    return d.toLocaleDateString('en-GB', { day: '2-digit', month: 'short', year: 'numeric' });
  }
  return d.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });
}

// unique id
const uid = () => Math.random().toString(36).slice(2, 9);

// Defaults
function defaultInvoice() {
  return {
    mode: 'invoice',        // 'invoice' | 'quote'
    logo: null,
    title: 'INVOICE',
    number: '001',
    from: '',
    billTo: '',
    shipTo: null,
    date: todayISO(),
    paymentTerms: '',
    dueDate: '',
    poNumber: null,
    lines: [
      { id: uid(), description: '', quantity: 1, rate: 0 },
    ],
    showQuantity: true,
    notes: '',
    terms: '',
    discount: null,         // { kind: 'percent'|'amount', value: number }
    tax: null,
    shipping: null,         // number
    amountPaid: 0,
    currency: detectCurrency(),
    dateFormat: 'US',       // 'US' | 'EU'
    paid: false,
    bank: null,             // { region, bankName, holder, ... } — see defaults below

    // ─── UI tweaks (per-invoice) ──────────────────────────────────────
    // Body font for data fields on the paper.
    //   'default' — mixed (current behavior: mono for dates/PO, sans for items)
    //   'sans'    — force everything to Inter Tight
    //   'mono'    — force everything to JetBrains Mono
    bodyFont: 'default',
  };
}

// Bank details per region — defines fields & labels
const BANK_REGIONS = {
  US: {
    label: 'United States',
    fields: [
      { key: 'bankName',      label: 'Bank name',      placeholder: 'Chase Bank' },
      { key: 'holder',        label: 'Account holder', placeholder: 'Your name or business' },
      { key: 'accountNumber', label: 'Account number', placeholder: '0000000000', mono: true },
      { key: 'routingNumber', label: 'Routing (ACH)',  placeholder: '000000000',  mono: true },
      { key: 'swift',         label: 'SWIFT / BIC',    placeholder: 'CHASUS33',   mono: true, optional: true },
      { key: 'reference',     label: 'Reference / Memo', placeholder: 'Invoice #', optional: true },
    ],
  },
  EU: {
    label: 'Europe (SEPA)',
    fields: [
      { key: 'bankName',      label: 'Bank name',      placeholder: 'BNP Paribas' },
      { key: 'holder',        label: 'Account holder', placeholder: 'Your name or business' },
      { key: 'iban',          label: 'IBAN',           placeholder: 'DE89 3704 0044 0532 0130 00', mono: true },
      { key: 'swift',         label: 'BIC / SWIFT',    placeholder: 'BNPAFRPP',   mono: true },
      { key: 'reference',     label: 'Reference',      placeholder: 'Invoice #',  optional: true },
    ],
  },
  UK: {
    label: 'United Kingdom',
    fields: [
      { key: 'bankName',      label: 'Bank name',      placeholder: 'Barclays' },
      { key: 'holder',        label: 'Account holder', placeholder: 'Your name or business' },
      { key: 'sortCode',      label: 'Sort code',      placeholder: '20-00-00',   mono: true },
      { key: 'accountNumber', label: 'Account number', placeholder: '00000000',   mono: true },
      { key: 'iban',          label: 'IBAN',           placeholder: 'GB29 NWBK …', mono: true, optional: true },
      { key: 'swift',         label: 'SWIFT / BIC',    placeholder: 'BARCGB22',   mono: true, optional: true },
      { key: 'reference',     label: 'Reference',      placeholder: 'Invoice #',  optional: true },
    ],
  },
  OTHER: {
    label: 'Other / International',
    fields: [
      { key: 'bankName',      label: 'Bank name',      placeholder: 'Bank name' },
      { key: 'holder',        label: 'Account holder', placeholder: 'Your name or business' },
      { key: 'accountNumber', label: 'Account number', placeholder: '0000000000', mono: true },
      { key: 'swift',         label: 'SWIFT / BIC',    placeholder: 'AAAA BB CC DDD', mono: true },
      { key: 'iban',          label: 'IBAN',           placeholder: 'IBAN if applicable', mono: true, optional: true },
      { key: 'extra',         label: 'Additional info', placeholder: 'Branch address, intermediary bank, etc.', textarea: true, optional: true },
      { key: 'reference',     label: 'Reference',      placeholder: 'Invoice #',  optional: true },
    ],
  },
};

function calcTotals(data) {
  const subtotal = data.lines.reduce((s, l) => s + (parseNumber(l.quantity) * parseNumber(l.rate)), 0);

  const discountAmt = data.discount
    ? (data.discount.kind === 'percent'
        ? subtotal * (parseNumber(data.discount.value) / 100)
        : parseNumber(data.discount.value))
    : 0;
  const afterDiscount = subtotal - discountAmt;

  const taxAmt = data.tax
    ? (data.tax.kind === 'percent'
        ? afterDiscount * (parseNumber(data.tax.value) / 100)
        : parseNumber(data.tax.value))
    : 0;

  const shippingAmt = data.shipping != null ? parseNumber(data.shipping) : 0;
  const total = afterDiscount + taxAmt + shippingAmt;
  const paid = parseNumber(data.amountPaid);
  const balance = total - paid;

  return { subtotal, discountAmt, afterDiscount, taxAmt, shippingAmt, total, paid, balance };
}

Object.assign(window, {
  CURRENCIES, CUR_MAP, curInfo, fmtMoney, fmtNumber, parseNumber,
  todayISO, fmtDate, uid, defaultInvoice, calcTotals, BANK_REGIONS,
  detectCurrency, detectCurrencyByLocale, detectCurrencyByIP,
  detectInitialCurrency, REGION_TO_CCY, IP_CCY_CACHE_KEY,
});
