// store.jsx — App state + persistence (in-memory; resets on tweak preset switch)
// Holds: incomes, subscriptions, splits, thresholds, currentMonth (for demo navigation)
//
// Splits model: a single global { free, investments, savings } that sums to 100.
// Subscriptions are paid from the Free bucket (so freeAfterSubs = free − totalSubs).

const uid = () => Math.random().toString(36).slice(2, 10);

function makeEmptyState() {
  return {
    splits: { free: 20, investments: 40, savings: 40 },
    thresholds: { low: 5, high: 10 },
    incomes: [],         // {id, name, amount, date}
    subscriptions: [],   // {id, name, amount, billingDay, active, startDate}
    history: {},         // ym -> {incomes:[], subsCharged:[{name,amount,date}]}
    // ── Coffee machines (separate sub-economy) ────────────────────────────
    coffee: {
      machines: [
        // {id, name, purchasePrice, purchaseDate}
      ],
      activeMachineId: null,         // selected for quick-add
      sales: [],                     // {id, machineId, date, amount, note}  — income deposit (e.g. 15-то и 30-то)
      expenses: [],                  // {id, machineId, date, kind, amount, note} kind: 'rent' | 'electricity' | 'beans' | 'milk' | 'cups' | 'service' | 'other'
    },
  };
}

// Fill in any missing top-level keys in `raw` from a fallback (default: empty).
// Used when loading from localStorage or importing JSON to absorb older shapes.
function normalizeState(raw, fallback) {
  const fb = fallback || makeEmptyState();
  const s = (raw && typeof raw === 'object') ? { ...raw } : {};
  if (!s.splits)        s.splits        = fb.splits;
  if (!s.thresholds)    s.thresholds    = fb.thresholds;
  if (!s.incomes)       s.incomes       = fb.incomes;
  if (!s.subscriptions) s.subscriptions = fb.subscriptions;
  if (!s.history)       s.history       = fb.history;
  if (!s.coffee)        s.coffee        = fb.coffee;
  return s;
}

// Realistic seed: April 2026 (current), some past months for History/Stats
function makeSeedState() {
  const today = new Date(); // demo "today"
  const y = today.getFullYear();
  const m = today.getMonth();
  const iso = (yy, mm, dd) => `${yy}-${String(mm+1).padStart(2,'0')}-${String(dd).padStart(2,'0')}`;

  // Current month incomes — demonstrate per-income override on bonus
  const incomes = [
    { id: uid(), name: 'Salary',      amount: 3200,  date: iso(y, m, 5)  },
    { id: uid(), name: 'Side income', amount: 480,   date: iso(y, m, 14) },
    { id: uid(), name: 'Freelance',   amount: 750,   date: iso(y, m, 22) },
  ];

  const subscriptions = [
    { id: uid(), name: 'Netflix',     amount: 13.99, billingDay: 28, active: true,  startDate: '2024-03-28' },
    { id: uid(), name: 'Spotify',     amount: 9.99,  billingDay: 12, active: true,  startDate: '2023-08-12' },
    { id: uid(), name: 'iCloud+',     amount: 2.99,  billingDay: 3,  active: true,  startDate: '2023-01-03' },
    { id: uid(), name: 'ChatGPT',     amount: 22.00, billingDay: 17, active: true,  startDate: '2024-09-17' },
    { id: uid(), name: 'HTB Academy', amount: 18.00, billingDay: 9,  active: true,  startDate: '2025-02-09' },
    { id: uid(), name: 'Notion',      amount: 8.00,  billingDay: 21, active: false, startDate: '2024-06-21' },
  ];

  // Synthetic history for last 5 months
  const history = {};
  const baseSubs = subscriptions.filter(s => s.active);
  for (let i = 1; i <= 5; i++) {
    const d = new Date(y, m - i, 1);
    const ym = `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}`;
    const variance = [3650, 4080, 3920, 4200, 3780][i-1];
    history[ym] = {
      incomes: [
        { id: uid(), name: 'Salary',      amount: 3200, date: iso(d.getFullYear(), d.getMonth(), 5) },
        { id: uid(), name: 'Side income', amount: variance - 3200, date: iso(d.getFullYear(), d.getMonth(), 18) },
      ],
      subsCharged: baseSubs.map(s => ({
        name: s.name, amount: s.amount,
        date: iso(d.getFullYear(), d.getMonth(), Math.min(s.billingDay, 28)),
      })),
    };
  }

  // Coffee seed — one machine, ~2 income deposits this month, expenses
  const machine1 = { id: uid(), name: 'Офис — lobby', purchasePrice: 1850, purchaseDate: '2025-09-15' };
  const coffeeSales = [];
  // Past payouts already collected this month: 15-то if today >= 15; 30-то if today >= 30
  if (today.getDate() >= 15) {
    coffeeSales.push({ id: uid(), machineId: machine1.id, date: iso(y, m, 15), amount: 240, note: '15-то' });
  }
  if (today.getDate() >= 30) {
    coffeeSales.push({ id: uid(), machineId: machine1.id, date: iso(y, m, 30), amount: 285, note: '30-то' });
  }
  const coffeeExpenses = [
    { id: uid(), machineId: machine1.id, date: iso(y, m, 1),  kind: 'rent',        amount: 80,    note: 'Наем място' },
    { id: uid(), machineId: machine1.id, date: iso(y, m, 1),  kind: 'electricity', amount: 22,    note: 'Ток' },
    { id: uid(), machineId: machine1.id, date: iso(y, m, 4),  kind: 'beans',       amount: 48,    note: '2кг specialty' },
    { id: uid(), machineId: machine1.id, date: iso(y, m, 8),  kind: 'cups',        amount: 14,    note: '200 бр.' },
    { id: uid(), machineId: machine1.id, date: iso(y, m, 12), kind: 'milk',        amount: 26,    note: '' },
    { id: uid(), machineId: machine1.id, date: iso(y, m, 19), kind: 'beans',       amount: 48,    note: '' },
    { id: uid(), machineId: machine1.id, date: iso(y, m, 24), kind: 'service',     amount: 65,    note: 'Профилактика' },
  ];

  return {
    splits: { free: 20, investments: 40, savings: 40 },
    thresholds: { low: 5, high: 10 },
    incomes, subscriptions, history,
    coffee: {
      machines: [machine1],
      activeMachineId: machine1.id,
      sales: coffeeSales,
      expenses: coffeeExpenses,
    },
  };
}

// React hook wrapping the store (caller chooses preset via key prop on App)
function useAppStore(initial) {
  const [state, setState] = React.useState(initial);

  const totalIncome = React.useMemo(
    () => state.incomes.reduce((a, b) => a + (Number(b.amount) || 0), 0),
    [state.incomes]
  );
  const activeSubs = React.useMemo(
    () => state.subscriptions.filter(s => s.active),
    [state.subscriptions]
  );
  const totalSubs = React.useMemo(
    () => activeSubs.reduce((a, b) => a + (Number(b.amount) || 0), 0),
    [activeSubs]
  );
  const subsPct = totalIncome > 0 ? (totalSubs / totalIncome) * 100 : 0;

  // Splits (in EUR) — global split applied to total income.
  const splitAmounts = React.useMemo(() => {
    const g = state.splits;
    return {
      free:        totalIncome * ((g.free        || 0) / 100),
      investments: totalIncome * ((g.investments || 0) / 100),
      savings:     totalIncome * ((g.savings     || 0) / 100),
    };
  }, [totalIncome, state.splits]);

  // Subs are paid out of the Free bucket.
  const freeAfterSubs = splitAmounts.free - totalSubs;

  // Per-income breakdown — what this single entry contributes (uses global split).
  const splitFor = React.useCallback((income) => {
    const g = state.splits;
    const amt = Number(income && income.amount) || 0;
    return {
      pct: g,
      free:        amt * ((g.free        || 0) / 100),
      investments: amt * ((g.investments || 0) / 100),
      savings:     amt * ((g.savings     || 0) / 100),
    };
  }, [state.splits]);

  // mutators — addIncome/addSub return the new id so callers can flash the row.
  const addIncome = (entry) => {
    const id = uid();
    setState(s => ({ ...s, incomes: [{ id, ...entry }, ...s.incomes] }));
    return id;
  };
  const editIncome = (id, patch) =>
    setState(s => ({ ...s, incomes: s.incomes.map(i => i.id === id ? { ...i, ...patch } : i) }));
  const deleteIncome = (id) =>
    setState(s => ({ ...s, incomes: s.incomes.filter(i => i.id !== id) }));

  const addSub = (entry) => {
    const id = uid();
    setState(s => ({ ...s, subscriptions: [{ id, active: true, ...entry }, ...s.subscriptions] }));
    return id;
  };
  const editSub = (id, patch) =>
    setState(s => ({ ...s, subscriptions: s.subscriptions.map(x => x.id === id ? { ...x, ...patch } : x) }));
  const deleteSub = (id) =>
    setState(s => ({ ...s, subscriptions: s.subscriptions.filter(x => x.id !== id) }));
  const toggleSub = (id) =>
    setState(s => ({ ...s, subscriptions: s.subscriptions.map(x => x.id === id ? { ...x, active: !x.active } : x) }));

  // ── Coffee mutators ───────────────────────────────────────────────────
  const ensureCoffee = (s) => s.coffee || { machines: [], activeMachineId: null, sales: [], expenses: [] };

  const addMachine = (entry) => {
    const id = uid();
    setState(s => {
      const c = ensureCoffee(s);
      const m = { id, ...entry };
      return { ...s, coffee: { ...c, machines: [...c.machines, m], activeMachineId: c.activeMachineId || id } };
    });
    return id;
  };
  const editMachine = (id, patch) =>
    setState(s => ({ ...s, coffee: { ...ensureCoffee(s), machines: ensureCoffee(s).machines.map(m => m.id === id ? { ...m, ...patch } : m) } }));
  const deleteMachine = (id) =>
    setState(s => {
      const c = ensureCoffee(s);
      const machines = c.machines.filter(m => m.id !== id);
      return { ...s, coffee: {
        ...c,
        machines,
        activeMachineId: c.activeMachineId === id ? (machines[0] && machines[0].id) || null : c.activeMachineId,
        sales: c.sales.filter(x => x.machineId !== id),
        expenses: c.expenses.filter(x => x.machineId !== id),
      } };
    });
  const setActiveMachine = (id) =>
    setState(s => ({ ...s, coffee: { ...ensureCoffee(s), activeMachineId: id } }));

  const addCoffeeSale = (entry) => {
    const id = uid();
    setState(s => ({ ...s, coffee: { ...ensureCoffee(s), sales: [{ id, ...entry }, ...ensureCoffee(s).sales] } }));
    return id;
  };
  const editCoffeeSale = (id, patch) =>
    setState(s => ({ ...s, coffee: { ...ensureCoffee(s), sales: ensureCoffee(s).sales.map(x => x.id === id ? { ...x, ...patch } : x) } }));
  const deleteCoffeeSale = (id) =>
    setState(s => ({ ...s, coffee: { ...ensureCoffee(s), sales: ensureCoffee(s).sales.filter(x => x.id !== id) } }));

  const addCoffeeExpense = (entry) => {
    const id = uid();
    setState(s => ({ ...s, coffee: { ...ensureCoffee(s), expenses: [{ id, ...entry }, ...ensureCoffee(s).expenses] } }));
    return id;
  };
  const editCoffeeExpense = (id, patch) =>
    setState(s => ({ ...s, coffee: { ...ensureCoffee(s), expenses: ensureCoffee(s).expenses.map(x => x.id === id ? { ...x, ...patch } : x) } }));
  const deleteCoffeeExpense = (id) =>
    setState(s => ({ ...s, coffee: { ...ensureCoffee(s), expenses: ensureCoffee(s).expenses.filter(x => x.id !== id) } }));

  const setCoffeeDefaultPrice = (p) => {}; // deprecated — coffee is income-deposit based now

  const setSplits = (splits) =>
    setState(s => ({ ...s, splits }));
  const setThresholds = (thresholds) =>
    setState(s => ({ ...s, thresholds }));

  const resetAll = () => setState(makeEmptyState());

  // ── Coffee derived stats (current month) ──────────────────────────────
  const coffee = state.coffee || { machines: [], activeMachineId: null, sales: [], expenses: [] };
  const today = new Date();
  const curYm = `${today.getFullYear()}-${String(today.getMonth()+1).padStart(2,'0')}`;
  const inCurMonth = (iso) => iso && iso.startsWith(curYm);

  const coffeeStats = React.useMemo(() => {
    const monthSales = coffee.sales.filter(s => inCurMonth(s.date));
    const monthExpenses = coffee.expenses.filter(x => inCurMonth(x.date));
    const revenue = monthSales.reduce((a, s) => a + (Number(s.amount) || 0), 0);
    const expenses = monthExpenses.reduce((a, x) => a + (Number(x.amount) || 0), 0);
    const net = revenue - expenses;
    return { revenue, expenses, net, monthSales, monthExpenses };
  }, [coffee.sales, coffee.expenses, curYm]);

  return {
    state, setState,
    totalIncome, activeSubs, totalSubs, subsPct,
    splitAmounts, freeAfterSubs, splitFor,
    addIncome, editIncome, deleteIncome,
    addSub, editSub, deleteSub, toggleSub,
    setSplits, setThresholds, resetAll,
    // coffee
    coffee, coffeeStats,
    addMachine, editMachine, deleteMachine, setActiveMachine,
    addCoffeeSale, editCoffeeSale, deleteCoffeeSale,
    addCoffeeExpense, editCoffeeExpense, deleteCoffeeExpense,
    setCoffeeDefaultPrice,
  };
}

// All-time stats helpers (used by Stats screen)
function computeAllTime(state, totals) {
  const { history } = state;
  const months = Object.keys(history).sort(); // ascending
  const monthly = months.map(ym => {
    const h = history[ym];
    const inc = h.incomes.reduce((a,b)=>a+b.amount,0);
    const subs = h.subsCharged.reduce((a,b)=>a+b.amount,0);
    return { ym, income: inc, subs, subsPct: inc > 0 ? subs/inc*100 : 0 };
  });
  // include current month (live)
  const curYm = ymKey(new Date());
  monthly.push({
    ym: curYm,
    income: totals.totalIncome,
    subs: totals.totalSubs,
    subsPct: totals.subsPct,
  });
  const totalEarned = monthly.reduce((a,b)=>a+b.income, 0);
  const totalSubsPaid = monthly.reduce((a,b)=>a+b.subs, 0);
  const totalSaved = monthly.reduce((a,b)=>a + b.income * ((state.splits.savings || 0)/100), 0);
  const totalInvested = monthly.reduce((a,b)=>a + b.income * ((state.splits.investments || 0)/100), 0);
  const avgSubsPct = monthly.length > 0
    ? monthly.reduce((a,b)=>a+b.subsPct, 0) / monthly.length : 0;
  return { monthly, totalEarned, totalSubsPaid, totalSaved, totalInvested, avgSubsPct };
}

Object.assign(window, {
  uid, makeEmptyState, makeSeedState, normalizeState, useAppStore, computeAllTime,
});
