// Finance helpers — pure, no React.
// Lifted into window for use across screen-finanzen.jsx, screen-dashboard.jsx
// and BackupView.

const MONTHS_LONG_DE = [
  'Januar','Februar','März','April','Mai','Juni',
  'Juli','August','September','Oktober','November','Dezember'
];
const MONTHS_SHORT_DE = ['Jan','Feb','Mär','Apr','Mai','Jun','Jul','Aug','Sep','Okt','Nov','Dez'];
const WEEKDAYS_SHORT_DE = ['So','Mo','Di','Mi','Do','Fr','Sa'];

function _parseDate(s) {
  if (!s) return null;
  if (s instanceof Date) return isNaN(s.getTime()) ? null : s;
  // Tolerate plain 'YYYY-MM-DD'
  const d = new Date(s);
  return isNaN(d.getTime()) ? null : d;
}

function fin_todayISO() {
  const d = new Date(), p = (n) => String(n).padStart(2, '0');
  return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())}`;
}

function fin_monthKeyOf(date) {
  const d = _parseDate(date);
  if (!d) return null;
  return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}`;
}

function fin_fmtMonthLabel(monthKey) {
  if (!monthKey) return '';
  const [y, m] = monthKey.split('-');
  const mi = parseInt(m, 10) - 1;
  if (isNaN(mi) || mi < 0 || mi > 11) return monthKey;
  return `${MONTHS_LONG_DE[mi]} ${y}`;
}

function fin_fmtMonthShort(monthKey) {
  if (!monthKey) return '';
  const [, m] = monthKey.split('-');
  const mi = parseInt(m, 10) - 1;
  return (mi >= 0 && mi <= 11) ? MONTHS_SHORT_DE[mi] : '';
}

// Human-friendly date label: Heute / Gestern / vor N Tagen / DD.MM.
function fin_fmtDateLabel(iso) {
  const d = _parseDate(iso);
  if (!d) return iso || '';
  const today = new Date(); today.setHours(0, 0, 0, 0);
  const dn = new Date(d); dn.setHours(0, 0, 0, 0);
  const diff = Math.round((today - dn) / 86400000);
  if (diff === 0) return 'Heute';
  if (diff === 1) return 'Gestern';
  if (diff > 1 && diff < 7) return `vor ${diff} Tagen`;
  if (diff === -1) return 'Morgen';
  const p = (n) => String(n).padStart(2, '0');
  return `${p(d.getDate())}.${p(d.getMonth() + 1)}.${d.getFullYear()}`;
}

// Build the month list to show — from earliest of {installedAt, oldest tx}
// to max of {today, latest tx}. Future months never appear unless a tx is in them.
function fin_buildMonthsRange(installedAt, transactions) {
  const today = new Date();
  let earliest = _parseDate(installedAt) || today;
  let latest = today;
  for (const tx of (transactions || [])) {
    const d = _parseDate(tx.date);
    if (!d) continue;
    if (d < earliest) earliest = d;
    if (d > latest) latest = d;
  }
  // Clamp to start-of-month to avoid edge cases.
  earliest = new Date(earliest.getFullYear(), earliest.getMonth(), 1);
  latest   = new Date(latest.getFullYear(),   latest.getMonth(),   1);

  const months = [];
  const cur = new Date(earliest);
  let safety = 0;
  while (cur <= latest && safety++ < 600) {
    const m = cur.getMonth(), y = cur.getFullYear();
    const key = `${y}-${String(m + 1).padStart(2, '0')}`;
    months.push({
      key,
      year: y,
      month: m,
      label: `${MONTHS_LONG_DE[m]} ${y}`,
      short: MONTHS_SHORT_DE[m],
    });
    cur.setMonth(cur.getMonth() + 1);
  }
  return months;
}

function fin_txInMonth(transactions, monthKey) {
  return (transactions || []).filter(t => fin_monthKeyOf(t.date) === monthKey);
}

function fin_txInYear(transactions, year) {
  return (transactions || []).filter(t => {
    const d = _parseDate(t.date); return d && d.getFullYear() === year;
  });
}

function fin_sumAgg(txs) {
  let inc = 0, exp = 0;
  for (const t of (txs || [])) {
    if (t.kind === 'in') inc += Number(t.amount) || 0;
    else if (t.kind === 'out') exp += Number(t.amount) || 0;
  }
  return { income: inc, expenses: exp, profit: inc - exp };
}

// Weekly bars W1..Wn (n = ceil(daysInMonth/7)) for current month
function fin_weeklyBars(transactions, year, month) {
  const daysInMonth = new Date(year, month + 1, 0).getDate();
  const numWeeks = Math.ceil(daysInMonth / 7);
  const bars = Array.from({ length: numWeeks }, (_, i) => ({ label: `W${i + 1}`, inc: 0, exp: 0 }));
  for (const tx of (transactions || [])) {
    const d = _parseDate(tx.date);
    if (!d || d.getFullYear() !== year || d.getMonth() !== month) continue;
    const day = d.getDate();
    const wi = Math.min(numWeeks - 1, Math.floor((day - 1) / 7));
    if (tx.kind === 'in') bars[wi].inc += Number(tx.amount) || 0;
    else if (tx.kind === 'out') bars[wi].exp += Number(tx.amount) || 0;
  }
  return bars;
}

// Year bars — one per active month. Only months that fall in the visible range.
function fin_yearBars(transactions, year, installedAt) {
  const months = fin_buildMonthsRange(installedAt, transactions).filter(m => m.year === year);
  return months.map(m => {
    const txs = fin_txInMonth(transactions, m.key);
    const { income, expenses } = fin_sumAgg(txs);
    return { label: m.short, inc: income, exp: expenses, monthKey: m.key };
  });
}

// Last-7-days income sparkline (one value per day, oldest → newest)
function fin_lastNDaysIncome(transactions, n = 7) {
  const out = [];
  const base = new Date(); base.setHours(0, 0, 0, 0);
  for (let i = n - 1; i >= 0; i--) {
    const d = new Date(base); d.setDate(base.getDate() - i);
    const iso = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
    const sum = (transactions || []).reduce((s, tx) => {
      if (tx.kind !== 'in') return s;
      const td = _parseDate(tx.date);
      if (!td) return s;
      const tiso = `${td.getFullYear()}-${String(td.getMonth() + 1).padStart(2, '0')}-${String(td.getDate()).padStart(2, '0')}`;
      return tiso === iso ? s + (Number(tx.amount) || 0) : s;
    }, 0);
    out.push(sum);
  }
  return out;
}

// Income per month for the mini sparkline. Returns the last `maxBars` months
// of the active range (since installation / oldest tx → today). When the user
// has data in Mai + Juni, this returns 2 numbers — one bar per month.
function fin_monthlyIncomeBars(transactions, installedAt, maxBars = 12) {
  const months = fin_buildMonthsRange(installedAt, transactions);
  const recent = months.slice(-maxBars);
  return recent.map(m => ({
    key: m.key,
    short: m.short,
    income: fin_sumAgg(fin_txInMonth(transactions, m.key)).income,
  }));
}

Object.assign(window, {
  MONTHS_LONG_DE, MONTHS_SHORT_DE, WEEKDAYS_SHORT_DE,
  fin_todayISO, fin_monthKeyOf, fin_fmtMonthLabel, fin_fmtMonthShort, fin_fmtDateLabel,
  fin_buildMonthsRange, fin_txInMonth, fin_txInYear, fin_sumAgg,
  fin_weeklyBars, fin_yearBars, fin_lastNDaysIncome, fin_monthlyIncomeBars,
});
