// Nordbank — money + loan-math helpers.
// All math is mocked; rates and effective-rate formula are intentionally
// approximate. Numbers are plausible for a sales-evaluation demo.

const COUNTRY_CURRENCY = {
  NO: 'NOK',
  DK: 'DKK',
  SE: 'SEK',
  FI: 'EUR',
};

const COUNTRY_META = {
  NO: { flag: '🇳🇴', label: { en: 'Norway',   no: 'Norge',   da: 'Norge',   sv: 'Norge',   fi: 'Norja'    } },
  DK: { flag: '🇩🇰', label: { en: 'Denmark',  no: 'Danmark', da: 'Danmark', sv: 'Danmark', fi: 'Tanska'   } },
  SE: { flag: '🇸🇪', label: { en: 'Sweden',   no: 'Sverige', da: 'Sverige', sv: 'Sverige', fi: 'Ruotsi'   } },
  FI: { flag: '🇫🇮', label: { en: 'Finland',  no: 'Finland', da: 'Finland', sv: 'Finland', fi: 'Suomi'    } },
};

// Locale to use for number formatting per UI lang.
const LOCALE_MAP = { no: 'nb-NO', da: 'da-DK', sv: 'sv-SE', fi: 'fi-FI', en: 'en-GB' };

function localeFor(lang) { return LOCALE_MAP[lang] || 'en-GB'; }

function formatMoney(amount, currency, lang, opts) {
  const o = opts || {};
  try {
    return new Intl.NumberFormat(localeFor(lang), {
      style: 'currency',
      currency,
      minimumFractionDigits: o.fraction ?? 0,
      maximumFractionDigits: o.fraction ?? 0,
    }).format(amount);
  } catch (e) {
    return amount.toFixed(0) + ' ' + currency;
  }
}

function formatNumber(value, lang, fraction) {
  try {
    return new Intl.NumberFormat(localeFor(lang), {
      minimumFractionDigits: fraction ?? 0,
      maximumFractionDigits: fraction ?? 0,
    }).format(value);
  } catch (e) {
    return String(value);
  }
}

function formatPercent(value, lang, fraction) {
  // value is e.g. 0.079 → "7.9%"
  try {
    return new Intl.NumberFormat(localeFor(lang), {
      style: 'percent',
      minimumFractionDigits: fraction ?? 1,
      maximumFractionDigits: fraction ?? 1,
    }).format(value);
  } catch (e) {
    return (value * 100).toFixed(fraction ?? 1) + '%';
  }
}

const NOMINAL_RATE = 0.079; // 7.9% annual nominal

// Monthly instalment for an annuity loan.
//   principal: amount in major units. nominalAnnualRate: e.g. 0.079
function monthlyInstalment(principal, nominalAnnualRate, termYears) {
  const n = Math.max(1, Math.round(termYears * 12));
  const r = nominalAnnualRate / 12;
  if (r === 0) return principal / n;
  return (principal * r) / (1 - Math.pow(1 + r, -n));
}

// Effective annual rate including a fixed monthly admin fee.
function effectiveRate(nominalAnnualRate, termYears, principal) {
  const monthlyFee = 39;
  const n = Math.max(1, Math.round(termYears * 12));
  const monthly = monthlyInstalment(principal, nominalAnnualRate, termYears) + monthlyFee;
  let i = nominalAnnualRate / 12;
  for (let k = 0; k < 50; k++) {
    if (i <= 0) i = 0.0001;
    const pow = Math.pow(1 + i, -n);
    const pv = monthly * (1 - pow) / i;
    const f = pv - principal;
    const dpv = monthly * (-(1 - pow) / (i * i) + n * Math.pow(1 + i, -n - 1) / i);
    const next = i - f / dpv;
    if (!isFinite(next)) break;
    if (Math.abs(next - i) < 1e-9) { i = next; break; }
    i = next;
  }
  const annual = Math.pow(1 + i, 12) - 1;
  return Math.max(nominalAnnualRate, Math.min(annual, 0.30));
}

// Per-currency amount range for the loan slider.
// NOK/SEK use the base range; DKK is ~0.75× (DKK is roughly 0.75 NOK in numeric size),
// EUR is ~0.10× (1 EUR ≈ 10 NOK/SEK ≈ 7.5 DKK).
const AMOUNT_RANGES = {
  NOK: { min: 10000, max: 600000, step: 10000, default: 150000 },
  SEK: { min: 10000, max: 600000, step: 10000, default: 150000 },
  DKK: { min:  7500, max: 450000, step:  7500, default: 112500 },
  EUR: { min:  1000, max:  60000, step:  1000, default:  15000 },
};

// Conversion factor relative to NOK (rough demo rates — refresh for production).
const CURRENCY_TO_NOK = { NOK: 1, SEK: 1, DKK: 1 / 0.75, EUR: 10 };

function convertAmount(amount, fromCurrency, toCurrency) {
  if (fromCurrency === toCurrency) return amount;
  const inNok = amount * (CURRENCY_TO_NOK[fromCurrency] || 1);
  return inNok / (CURRENCY_TO_NOK[toCurrency] || 1);
}

// Snap a converted amount to its target currency's step, and clamp to range.
function snapAmount(amount, currency) {
  const r = AMOUNT_RANGES[currency] || AMOUNT_RANGES.NOK;
  const snapped = Math.round(amount / r.step) * r.step;
  return Math.max(r.min, Math.min(r.max, snapped));
}

function quoteLoan(amount, termYears) {
  const monthly = monthlyInstalment(amount, NOMINAL_RATE, termYears);
  const effective = effectiveRate(NOMINAL_RATE, termYears, amount);
  const totalPayable = monthly * Math.round(termYears * 12);
  const totalCost = totalPayable - amount;
  return {
    nominalRate: NOMINAL_RATE,
    effectiveRate: effective,
    monthly,
    totalPayable,
    totalCost,
  };
}

// Loan-protection insurance premium.
// Uses a flat-fee table keyed by loan term (years), expressed as a fraction of
// the loan amount over the full term.
//   premium_total   = loan_amount \u00d7 rate(term)
//   monthly_premium = premium_total / (term_years \u00d7 12)
//   minimum_monthly = 49 (in the loan's currency; numeric floor)
const INSURANCE_RATE_TABLE = [
  { years: 1,  rate: 0.012 },
  { years: 2,  rate: 0.020 },
  { years: 3,  rate: 0.028 },
  { years: 5,  rate: 0.040 },
  { years: 7,  rate: 0.052 },
  { years: 10, rate: 0.068 },
  { years: 15, rate: 0.090 },
];
const MIN_INSURANCE_MONTHLY = 49;

function insuranceRateForTerm(termYears) {
  const exact = INSURANCE_RATE_TABLE.find(r => r.years === termYears);
  if (exact) return exact.rate;
  if (termYears <= INSURANCE_RATE_TABLE[0].years) return INSURANCE_RATE_TABLE[0].rate;
  const last = INSURANCE_RATE_TABLE[INSURANCE_RATE_TABLE.length - 1];
  if (termYears >= last.years) return last.rate;
  for (let i = 0; i < INSURANCE_RATE_TABLE.length - 1; i++) {
    const a = INSURANCE_RATE_TABLE[i], b = INSURANCE_RATE_TABLE[i + 1];
    if (termYears > a.years && termYears < b.years) {
      const t = (termYears - a.years) / (b.years - a.years);
      return a.rate + t * (b.rate - a.rate);
    }
  }
  return last.rate;
}

function insurancePremium(loanAmount, termYears) {
  const rate = insuranceRateForTerm(termYears);
  const premiumTotal = loanAmount * rate;
  const n = Math.max(1, Math.round(termYears * 12));
  return Math.max(MIN_INSURANCE_MONTHLY, premiumTotal / n);
}

// Generate a friendly confirmation number.
function makeConfirmationNumber() {
  const n = Math.floor(Math.random() * 9000000) + 1000000;
  return 'NB-' + n.toString().slice(0, 3) + '-' + n.toString().slice(3);
}

Object.assign(window, {
  COUNTRY_CURRENCY,
  COUNTRY_META,
  LOCALE_MAP,
  localeFor,
  formatMoney,
  formatNumber,
  formatPercent,
  monthlyInstalment,
  effectiveRate,
  quoteLoan,
  insurancePremium,
  insuranceRateForTerm,
  INSURANCE_RATE_TABLE,
  MIN_INSURANCE_MONTHLY,
  makeConfirmationNumber,
  NOMINAL_RATE,
  AMOUNT_RANGES,
  CURRENCY_TO_NOK,
  convertAmount,
  snapAmount,
});
