// Money — seed data + persistence helpers.
// On first launch we seed localStorage with sensible defaults.
// On subsequent launches we hydrate from localStorage.

const LS = {
  accounts: 'money:accounts',
  categories: 'money:catExtras',          // user-added / mutated categories overlay preset
  catPreset: 'money:catPreset',           // mutated preset categories
  subs: 'money:subs',
  credits: 'money:credits',
  incomeSources: 'money:incomeSources',
  goals: 'money:goals',
  notifSettings: 'money:notif:settings',
};

const PRESET_CATEGORIES = [
  // Daily
  { id: 'food',     title: 'Продукты',     spent: 0, planned: 28000, icon: 'cart',     color: '#C77B4A' },
  { id: 'cafe',     title: 'Кафе',         spent: 0, planned: 15000, icon: 'coffee',   color: '#D4A23A' },
  { id: 'delivery', title: 'Доставка еды', spent: 0, planned: 8000,  icon: 'cart',     color: '#E08856' },
  // Transport
  { id: 'taxi',     title: 'Такси',        spent: 0, planned: 6000,  icon: 'car',      color: '#5B8BAA' },
  { id: 'transport',title: 'Транспорт',    spent: 0, planned: 4000,  icon: 'car',      color: '#7AA4BD' },
  { id: 'auto',     title: 'Авто',         spent: 0, planned: 10000, icon: 'car',      color: '#4A6F8A' },
  // Home
  { id: 'home',     title: 'Жильё',        spent: 0, planned: 45000, icon: 'bank',     color: '#8A7B5A' },
  { id: 'utilities',title: 'Коммуналка',   spent: 0, planned: 7000,  icon: 'bank',     color: '#A89878' },
  { id: 'telecom',  title: 'Связь',        spent: 0, planned: 1500,  icon: 'music',    color: '#6B8DC4' },
  { id: 'household',title: 'Для дома',     spent: 0, planned: 4000,  icon: 'gift',     color: '#B9A17C' },
  // Self
  { id: 'health',   title: 'Здоровье',     spent: 0, planned: 8000,  icon: 'heart',    color: '#5BA68A' },
  { id: 'fitness',  title: 'Спорт',        spent: 0, planned: 5000,  icon: 'heart',    color: '#3DBA85' },
  { id: 'beauty',   title: 'Красота',      spent: 0, planned: 5000,  icon: 'heart',    color: '#C68FB8' },
  { id: 'clothes',  title: 'Одежда',       spent: 0, planned: 8000,  icon: 'shirt',    color: '#A38869' },
  // Mind
  { id: 'edu',      title: 'Образование',  spent: 0, planned: 12000, icon: 'book',     color: '#7A6BB8' },
  { id: 'books',    title: 'Книги и медиа',spent: 0, planned: 2000,  icon: 'book',     color: '#9B6DFF' },
  { id: 'subs',     title: 'Подписки',     spent: 0, planned: 4500,  icon: 'music',    color: '#6D8FFF' },
  { id: 'gadgets',  title: 'Гаджеты',      spent: 0, planned: 5000,  icon: 'card',     color: '#5670B8' },
  // Fun
  { id: 'fun',      title: 'Развлечения',  spent: 0, planned: 7000,  icon: 'film',     color: '#FF3D9A' },
  { id: 'hobby',    title: 'Хобби',        spent: 0, planned: 3000,  icon: 'edit',     color: '#C68FB8' },
  // Social
  { id: 'travel',   title: 'Путешествия',  spent: 0, planned: 50000, icon: 'plane',    color: '#3DDBDB' },
  { id: 'gifts',    title: 'Подарки',      spent: 0, planned: 3000,  icon: 'gift',     color: '#FF6DB1' },
  { id: 'pets',     title: 'Питомец',      spent: 0, planned: 3000,  icon: 'heart',    color: '#B86F8E' },
  // Fallback
  { id: 'other',    title: 'Прочее',       spent: 0, planned: 5000,  icon: 'plus',     color: '#9A938A' },
];

const SEED = {
  accounts: [
    { id: 'tin',  bank: 'Тинькофф', title: 'Основная',      balance: 142800, color: '#FFDD2D', last4: '4520', main: true },
    { id: 'sber', bank: 'Сбер',     title: 'Накопительная', balance: 248500, color: '#1AB55D', last4: '8801' },
    { id: 'alfa', bank: 'Альфа',    title: 'Кэшбэк',        balance: 32400,  color: '#EF3124', last4: '2317' },
  ],
  subs: [
    { id: 'sub-spotify', title: 'Spotify',        amount: 299,  day: 12, color: '#1DB954', cat: 'Музыка',  logo: 'S',  accountId: 'tin', active: true },
    { id: 'sub-yaplus',  title: 'Яндекс Плюс',    amount: 399,  day: 4,  color: '#FFDB4D', cat: 'Сервисы', logo: 'Я',  accountId: 'tin', active: true },
    { id: 'sub-icloud',  title: 'iCloud 200GB',   amount: 249,  day: 18, color: '#2997FF', cat: 'Облако',  logo: '☁', accountId: 'tin', active: true },
    { id: 'sub-copilot', title: 'GitHub Copilot', amount: 890,  day: 22, color: '#24292E', cat: 'Работа',  logo: 'GH', accountId: 'tin', active: true },
    { id: 'sub-notion',  title: 'Notion',         amount: 800,  day: 8,  color: '#2D2D2D', cat: 'Работа',  logo: 'N',  accountId: 'tin', active: true },
    { id: 'sub-nike',    title: 'Nike Training',  amount: 1099, day: 1,  color: '#FA5400', cat: 'Спорт',   logo: 'NK', accountId: 'tin', active: true },
  ],
  credits: [
    { id: 'cr-mortgage', bank: 'Тинькофф', title: 'Ипотека', total: 4800000, paid: 1240000, rate: 8.9,  monthly: 38400, years: 15, nextDate: '05 нояб', accountId: 'tin' },
    { id: 'cr-auto',     bank: 'Альфа',    title: 'Авто',    total: 850000,  paid: 612000,  rate: 12.5, monthly: 22100, years: 3,  nextDate: '12 нояб', accountId: 'alfa' },
  ],
  incomeSources: [
    { id: 'salary',    title: 'Зарплата',   amount: 180000, day: 5,  type: 'recurring', icon: 'briefcase', color: '#0F8A5A', accountId: 'tin',
      distributionRules: [ { accountId: 'tin', percent: 60 }, { accountId: 'sber', percent: 25 }, { accountId: 'alfa', percent: 15 } ] },
    { id: 'freelance', title: 'Фриланс',    amount: 45000,  day: 20, type: 'recurring', icon: 'edit',      color: '#C77B4A', accountId: 'tin' },
    { id: 'invest',    title: 'Инвестиции', amount: 12000,  day: 25, type: 'recurring', icon: 'invest',    color: '#5B8BAA', accountId: 'sber' },
  ],
  goals: [
    {
      id: 'goal-dubai', title: 'Переезд в Дубай', emoji: '🏝',
      target: 3000000, saved: 612000, accountId: 'sber',
      monthly: 45000, deadline: 'Авг 2028',
      milestones: [
        { at: 500000,  label: 'Виза + перелёт',   done: true  },
        { at: 1200000, label: 'Депозит за жильё', done: false },
        { at: 2400000, label: '6 мес. подушки',   done: false },
        { at: 3000000, label: 'Цель достигнута',  done: false },
      ],
    },
  ],
};

function loadLS(key, fallback) {
  try { const v = localStorage.getItem(key); return v ? JSON.parse(v) : fallback; }
  catch { return fallback; }
}
function saveLS(key, value) {
  try { localStorage.setItem(key, JSON.stringify(value)); } catch {}
}

// Merge preset + overrides + user-added.
function loadCategories() {
  const preset = PRESET_CATEGORIES.map(c => ({ ...c }));
  // overrides — same id, mutated fields
  const overrides = loadLS(LS.catPreset, []);
  if (Array.isArray(overrides)) {
    for (const o of overrides) {
      const i = preset.findIndex(c => c.id === o.id);
      if (i >= 0) preset[i] = { ...preset[i], ...o };
    }
  }
  const extras = loadLS(LS.categories, []);
  return [...preset, ...(Array.isArray(extras) ? extras : [])];
}

// DATA object: starting collections, computed totals, formatter helpers.
const DATA = {
  user: { name: 'Александр', email: 'alex@mail.ru' },
  // Default conversion rates — replaced by Settings → «Обновить курсы»
  rates: loadLS('money:rates', { usd: 89.75, eur: 97.4, manual: false, updated: null }),
  month: { name: 'Октябрь', year: 2026, idx: 9 },
  prevMonth: { name: 'Сентябрь', saved: 18420, percent: -11, status: 'saved' },
  income:  { planned: 240000, actual: 195000 },
  expense: { planned: 178000, actual: 152430 },

  accounts:      loadLS(LS.accounts, SEED.accounts),
  categories:    loadCategories(),
  subs:          loadLS(LS.subs, SEED.subs),
  credits:       loadLS(LS.credits, SEED.credits),
  incomeSources: loadLS(LS.incomeSources, SEED.incomeSources),
  goals:         loadLS(LS.goals, SEED.goals),

  // The `upcoming` block is derived from subs+credits+incomeSources on the fly
  // (used by Home + Calendar). Keeping a few demo entries for first-launch UX.
  upcoming: [],

  // Empty until the user creates one.
  txs: [],
  monthsHistory: [
    { m: 'Май', inc: 215, exp: 168, plannedExp: 175 },
    { m: 'Июн', inc: 230, exp: 182, plannedExp: 180 },
    { m: 'Июл', inc: 225, exp: 171, plannedExp: 178 },
    { m: 'Авг', inc: 240, exp: 195, plannedExp: 180 },
    { m: 'Сен', inc: 238, exp: 164, plannedExp: 180 },
    { m: 'Окт', inc: 195, exp: 152, plannedExp: 178 },
  ],
  notifications: [],
};

// Pick the credit payment for a given calendar month using paymentSchedule
// (differentiated payments) when available; falls back to monthly (annuity).
//
// Schedule entry shape (AI returns DD.MM.YYYY by default):
//   { date: "05.03.2027", amount: 38400, principal?: number, interest?: number }
function creditPaymentForMonth(c, year, month /* 1..12 */) {
  if (Array.isArray(c.paymentSchedule) && c.paymentSchedule.length) {
    const ymKey = String(month).padStart(2, '0') + '.' + year;
    const hit = c.paymentSchedule.find(p => {
      if (!p || !p.date) return false;
      // Match "DD.MM.YYYY" — robust to "5.03.2027" / "05/03/2027" / "2027-03-05".
      const s = String(p.date).replace(/[-/]/g, '.');
      // DD.MM.YYYY
      const m1 = s.match(/^(\d{1,2})\.(\d{1,2})\.(\d{4})$/);
      if (m1) return parseInt(m1[2], 10) === month && parseInt(m1[3], 10) === year;
      // YYYY.MM.DD
      const m2 = s.match(/^(\d{4})\.(\d{1,2})\.(\d{1,2})$/);
      if (m2) return parseInt(m2[2], 10) === month && parseInt(m2[1], 10) === year;
      return false;
    });
    if (hit) return Math.round(hit.amount);
  }
  return c.monthly;
}

// Sum of all future scheduled payments (date >= today).
// Returns null when we don't have enough info to compute accurately.
function creditFuturePaymentsTotal(c, todayDate) {
  const today = todayDate || new Date();
  const todayKey = today.toISOString().slice(0, 10);

  if (Array.isArray(c.paymentSchedule) && c.paymentSchedule.length) {
    let sum = 0, count = 0;
    for (const p of c.paymentSchedule) {
      if (!p || !p.date || !p.amount) continue;
      const s = String(p.date).replace(/[-/]/g, '.');
      const m1 = s.match(/^(\d{1,2})\.(\d{1,2})\.(\d{4})$/);
      const m2 = s.match(/^(\d{4})\.(\d{1,2})\.(\d{1,2})$/);
      let iso;
      if (m1) iso = `${m1[3]}-${m1[2].padStart(2,'0')}-${m1[1].padStart(2,'0')}`;
      else if (m2) iso = `${m2[1]}-${m2[2].padStart(2,'0')}-${m2[3].padStart(2,'0')}`;
      if (!iso) continue;
      if (iso >= todayKey) { sum += p.amount; count++; }
    }
    return { total: Math.round(sum), count, source: 'schedule' };
  }

  // Annuity fallback: number of months remaining = ceil(remaining / monthly).
  const remaining = (c.total || 0) - (c.paid || 0);
  if (!c.monthly || c.monthly <= 0 || remaining <= 0) return null;
  // Use an annuity-aware month count when we have a rate. Otherwise rough estimate.
  let monthsLeft;
  if (c.rate && c.rate > 0) {
    const r = c.rate / 100 / 12;
    // n = -log(1 - r*P / M) / log(1 + r)
    const ratio = 1 - (r * remaining) / c.monthly;
    if (ratio > 0 && ratio < 1) monthsLeft = Math.ceil(-Math.log(ratio) / Math.log(1 + r));
    else monthsLeft = Math.ceil(remaining / c.monthly);
  } else {
    monthsLeft = Math.ceil(remaining / c.monthly);
  }
  return { total: Math.round(c.monthly * monthsLeft), count: monthsLeft, source: 'annuity' };
}

// Find the day-of-month a credit payment falls on, in a given month.
// Schedule takes priority over c.nextDate.
function creditPaymentDayForMonth(c, year, month /* 1..12 */) {
  if (Array.isArray(c.paymentSchedule) && c.paymentSchedule.length) {
    const hit = c.paymentSchedule.find(p => {
      if (!p || !p.date) return false;
      const s = String(p.date).replace(/[-/]/g, '.');
      const m1 = s.match(/^(\d{1,2})\.(\d{1,2})\.(\d{4})$/);
      if (m1) return parseInt(m1[2], 10) === month && parseInt(m1[3], 10) === year;
      const m2 = s.match(/^(\d{4})\.(\d{1,2})\.(\d{1,2})$/);
      if (m2) return parseInt(m2[2], 10) === month && parseInt(m2[1], 10) === year;
      return false;
    });
    if (hit) {
      const s = String(hit.date).replace(/[-/]/g, '.');
      const m1 = s.match(/^(\d{1,2})\./);
      const m2 = s.match(/^\d{4}\.\d{1,2}\.(\d{1,2})$/);
      if (m1) return parseInt(m1[1], 10);
      if (m2) return parseInt(m2[1], 10);
    }
  }
  return parseInt(c.nextDate, 10) || 1;
}

function recomputeUpcoming() {
  const list = [];
  const MONTHS = ['янв','фев','мар','апр','май','июн','июл','авг','сен','окт','нояб','дек'];
  const now = new Date();
  const nextDays = 14;
  for (let i = 0; i < nextDays; i++) {
    const d = new Date(now.getFullYear(), now.getMonth(), now.getDate() + i);
    const day = d.getDate();
    const y = d.getFullYear();
    const m = d.getMonth() + 1;
    const mn = MONTHS[d.getMonth()];
    const dateStr = `${String(day).padStart(2,'0')} ${mn}`;
    DATA.subs.filter(s => s.active !== false && s.day === day).forEach(s => list.push({
      id: 'up-sub-' + s.id + '-' + i, title: s.title, amount: s.amount, date: dateStr, day,
      tag: 'Подписка', catId: 'subs', isSub: true,
    }));
    DATA.credits.forEach(c => {
      if (creditPaymentDayForMonth(c, y, m) !== day) return;
      const amount = creditPaymentForMonth(c, y, m);
      list.push({
        id: 'up-cr-' + c.id + '-' + i, title: c.title, amount, date: dateStr, day,
        tag: 'Кредит', catId: null, isCredit: true,
      });
    });
    DATA.incomeSources.filter(s => s.day === day).forEach(s => list.push({
      id: 'up-inc-' + s.id + '-' + i, title: s.title, amount: s.amount, date: dateStr, day,
      tag: 'Доход', income: true,
    }));
  }
  DATA.upcoming = list;
  return list;
}

// Total balance — recomputed on demand.
function recomputeTotals() {
  DATA.totalBalance = DATA.accounts.reduce((s,a) => s + (a.balance || 0), 0);
}

// Persist helpers — called by app.jsx when state changes.
function persistAccounts() { saveLS(LS.accounts, DATA.accounts); recomputeTotals(); }
function persistSubs()     { saveLS(LS.subs, DATA.subs); recomputeUpcoming(); }
function persistCredits()  { saveLS(LS.credits, DATA.credits); recomputeUpcoming(); }
function persistIncomeSources() { saveLS(LS.incomeSources, DATA.incomeSources); recomputeUpcoming(); }
function persistGoals()    { saveLS(LS.goals, DATA.goals); }

// Categories: split between preset overrides and user extras.
function persistCategories() {
  const presetIds = new Set(PRESET_CATEGORIES.map(c => c.id));
  const overrides = DATA.categories
    .filter(c => presetIds.has(c.id))
    .map(c => ({ id: c.id, title: c.title, planned: c.planned, color: c.color, emoji: c.emoji, archived: !!c.archived, icon: c.icon }));
  const extras = DATA.categories.filter(c => !presetIds.has(c.id));
  saveLS(LS.catPreset, overrides);
  saveLS(LS.categories, extras);
}

// Add a new category (used by AI suggestion + Categories screen).
function addCategory(cat) {
  const c = { spent: 0, planned: 0, icon: 'plus', color: '#9A938A', ...cat };
  if (!c.id) c.id = 'c_' + Date.now();
  if (DATA.categories.find(x => x.id === c.id)) return c;
  DATA.categories.push(c);
  persistCategories();
  return c;
}

function deleteCategory(id) {
  const i = DATA.categories.findIndex(c => c.id === id);
  if (i < 0) return;
  // Preset cats — archive instead of delete (avoid breaking history).
  const presetIds = new Set(PRESET_CATEGORIES.map(x => x.id));
  if (presetIds.has(id)) {
    DATA.categories[i] = { ...DATA.categories[i], archived: true };
  } else {
    DATA.categories.splice(i, 1);
  }
  persistCategories();
}

function updateCategory(id, patch) {
  const i = DATA.categories.findIndex(c => c.id === id);
  if (i < 0) return;
  DATA.categories[i] = { ...DATA.categories[i], ...patch };
  persistCategories();
}

// Account CRUD
function addAccount(acc) {
  const a = { color: '#6B8DC4', balance: 0, last4: '0000', ...acc };
  if (!a.id) a.id = 'acc_' + Date.now();
  // Only one main allowed.
  if (a.main) DATA.accounts.forEach(x => x.main = false);
  DATA.accounts.push(a);
  persistAccounts();
  return a;
}
function updateAccount(id, patch) {
  const i = DATA.accounts.findIndex(a => a.id === id);
  if (i < 0) return;
  if (patch.main) DATA.accounts.forEach(x => x.main = false);
  DATA.accounts[i] = { ...DATA.accounts[i], ...patch };
  persistAccounts();
}
function deleteAccount(id) {
  DATA.accounts = DATA.accounts.filter(a => a.id !== id);
  if (DATA.accounts.length && !DATA.accounts.find(a => a.main)) DATA.accounts[0].main = true;
  persistAccounts();
}

// Goals CRUD
function addGoal(g) {
  const x = { saved: 0, monthly: 5000, milestones: [], emoji: '🎯', ...g };
  if (!x.id) x.id = 'goal_' + Date.now();
  DATA.goals.push(x);
  persistGoals();
  return x;
}
function updateGoal(id, patch) {
  const i = DATA.goals.findIndex(g => g.id === id);
  if (i < 0) return;
  DATA.goals[i] = { ...DATA.goals[i], ...patch };
  persistGoals();
}
function deleteGoal(id) {
  DATA.goals = DATA.goals.filter(g => g.id !== id);
  persistGoals();
}

// First-launch fix-up.
recomputeTotals();
recomputeUpcoming();
// Backwards-compat — older calls use `goal` (singular).
Object.defineProperty(DATA, 'goal', { get() { return DATA.goals[0]; }, configurable: true });
Object.defineProperty(DATA, 'usdRate', { get() { return DATA.rates.usd; }, configurable: true });

Object.assign(window, {
  DATA, LS, PRESET_CATEGORIES, SEED,
  loadLS, saveLS,
  addCategory, deleteCategory, updateCategory,
  addAccount, updateAccount, deleteAccount,
  addGoal, updateGoal, deleteGoal,
  persistAccounts, persistCategories, persistSubs, persistCredits, persistIncomeSources, persistGoals,
  recomputeUpcoming, recomputeTotals,
  creditPaymentForMonth, creditPaymentDayForMonth, creditFuturePaymentsTotal,
});
