/* ============================================================
   Forja 3D — Data store (localStorage-backed) + helpers
   Exposes to window: useStore, store, fmt, helpers
   ============================================================ */
const STORAGE_KEY = 'forja3d_v3';

const uid = () => Math.random().toString(36).slice(2, 9);
const today = () => new Date().toISOString().slice(0, 10);

/* ---------- seed data ---------- */
function seed() {
  const fPLA = uid(), fPETG = uid(), fPLAplus = uid(), fTPU = uid(), fSilk = uid();
  return {
    settings: {
      printerName: 'Ender 3 V3',
      printerCost: 2500,
      printerLifeHours: 5000,
      powerWatts: 150,
      energyCostKwh: 0.92,
      laborPerHour: 5,
      defaultMargin: 120,
      failRate: 8,
      defaultPackaging: 2.5,
      marketplaceFee: 14,
    },
    filaments: [
      { id: fPLA,     name: 'PLA Preto',          type: 'PLA',  brand: 'Voolt',   color: '#1a1a1a', costPerKg: 90,  spoolWeight: 1000, remaining: 640 },
      { id: fPLAplus, name: 'PLA+ Laranja',       type: 'PLA+', brand: '3D Lab',  color: '#FF6A1A', costPerKg: 98,  spoolWeight: 1000, remaining: 820 },
      { id: fPETG,    name: 'PETG Transparente',  type: 'PETG', brand: 'GTMax',   color: '#cfe8ff', costPerKg: 120, spoolWeight: 1000, remaining: 310 },
      { id: fSilk,    name: 'PLA Silk Dourado',   type: 'Silk', brand: 'Voolt',   color: '#d4af37', costPerKg: 135, spoolWeight: 1000, remaining: 180 },
      { id: fTPU,     name: 'TPU Flexível Preto', type: 'TPU',  brand: 'Sunlu',   color: '#222222', costPerKg: 160, spoolWeight: 500,  remaining: 90  },
    ],
    debts: [
      { id: uid(), name: 'Impressora Ender 3 V3', total: 2500, paid: 1600, note: 'Parcelado 10x — Casas Bahia', kind: 'impressora' },
      { id: uid(), name: 'Lote de Filamentos',    total: 600,  paid: 480,  note: 'Compra atacado fornecedor', kind: 'insumo' },
      { id: uid(), name: 'Mesa + ferramentas',    total: 450,  paid: 150,  note: 'Bancada, alicates, espátulas', kind: 'equipamento' },
    ],
    expenses: [
      { id: uid(), date: '2026-06-06', description: 'Filamento PLA+ 1kg', category: 'Filamento', amount: 92 },
      { id: uid(), date: '2026-06-04', description: 'Conta de energia (rateio)', category: 'Energia', amount: 48 },
      { id: uid(), date: '2026-06-02', description: 'Caixas de papelão (50un)', category: 'Embalagem', amount: 65 },
      { id: uid(), date: '2026-05-28', description: 'Bico 0.4mm reposição (x3)', category: 'Manutenção', amount: 35 },
      { id: uid(), date: '2026-05-20', description: 'Anúncio impulsionado Shopee', category: 'Marketing', amount: 40 },
    ],
    sales: [
      { id: uid(), date: '2026-06-08', product: 'Suporte de fone gamer', channel: 'Shopee',        price: 95,  cost: 38, qty: 1 },
      { id: uid(), date: '2026-06-05', product: 'Vaso geométrico G',      channel: 'Encomenda',     price: 119, cost: 61, qty: 1 },
      { id: uid(), date: '2026-06-03', product: 'Kit organizador mesa',   channel: 'Mercado Livre', price: 65,  cost: 27, qty: 3 },
      { id: uid(), date: '2026-05-30', product: 'Luminária lua 15cm',     channel: 'Instagram',     price: 149, cost: 84, qty: 1 },
      { id: uid(), date: '2026-05-26', product: 'Porta-treco gato',       channel: 'Shopee',        price: 45,  cost: 18, qty: 2 },
    ],
    products: [
      { id: uid(), name: 'Suporte de fone gamer', filamentId: fPETG,    weightG: 85,  printTimeMin: 240, price: 95,  color: '#cfe8ff' },
      { id: uid(), name: 'Vaso geométrico G',     filamentId: fPLAplus, weightG: 145, printTimeMin: 420, price: 119, color: '#FF6A1A' },
      { id: uid(), name: 'Kit organizador mesa',  filamentId: fPLA,     weightG: 60,  printTimeMin: 180, price: 65,  color: '#1a1a1a' },
      { id: uid(), name: 'Luminária lua 15cm',    filamentId: fSilk,    weightG: 180, printTimeMin: 540, price: 149, color: '#d4af37' },
    ],
    prints: [
      { id: uid(), date: '2026-06-08', product: 'Suporte de fone gamer', filamentId: fPETG,    grams: 85,  timeMin: 240, status: 'sucesso' },
      { id: uid(), date: '2026-06-07', product: 'Vaso geométrico G',      filamentId: fPLAplus, grams: 145, timeMin: 420, status: 'sucesso' },
      { id: uid(), date: '2026-06-06', product: 'Teste calibração',       filamentId: fPLA,     grams: 22,  timeMin: 55,  status: 'falha' },
      { id: uid(), date: '2026-06-05', product: 'Kit organizador (x3)',   filamentId: fPLA,     grams: 180, timeMin: 540, status: 'sucesso' },
      { id: uid(), date: '2026-06-03', product: 'Luminária lua 15cm',     filamentId: fSilk,    grams: 180, timeMin: 540, status: 'sucesso' },
    ],
  };
}

/* ---------- store core ---------- */
function load() {
  try {
    const raw = localStorage.getItem(STORAGE_KEY);
    if (raw) return JSON.parse(raw);
  } catch (e) {}
  return seed();
}

let state = load();
const listeners = new Set();
let _applyingRemote = false;        // true enquanto aplicamos mudança vinda da nuvem
let _syncHandler = null;            // callback(state) → empurra pra nuvem
const EMPTY = { settings: {}, filaments: [], debts: [], expenses: [], sales: [], products: [], prints: [] };
function persist() { try { localStorage.setItem(STORAGE_KEY, JSON.stringify(state)); } catch (e) {} }
function emit() {
  persist();
  if (_syncHandler && !_applyingRemote) _syncHandler(state);
  listeners.forEach((l) => l());
}

const store = {
  get: () => state,
  set(patch) { state = { ...state, ...(typeof patch === 'function' ? patch(state) : patch) }; emit(); },
  subscribe(fn) { listeners.add(fn); return () => listeners.delete(fn); },

  /* settings */
  updateSettings(patch) { store.set({ settings: { ...state.settings, ...patch } }); },

  /* filaments */
  addFilament(f) { store.set({ filaments: [{ id: uid(), ...f }, ...state.filaments] }); },
  updateFilament(id, patch) { store.set({ filaments: state.filaments.map((x) => x.id === id ? { ...x, ...patch } : x) }); },
  removeFilament(id) { store.set({ filaments: state.filaments.filter((x) => x.id !== id) }); },

  /* debts */
  addDebt(d) { store.set({ debts: [{ id: uid(), paid: 0, ...d }, ...state.debts] }); },
  payDebt(id, amount) { store.set({ debts: state.debts.map((x) => x.id === id ? { ...x, paid: Math.min(x.total, x.paid + amount) } : x) }); },
  updateDebt(id, patch) { store.set({ debts: state.debts.map((x) => x.id === id ? { ...x, ...patch } : x) }); },
  removeDebt(id) { store.set({ debts: state.debts.filter((x) => x.id !== id) }); },

  /* expenses */
  addExpense(e) { store.set({ expenses: [{ id: uid(), ...e }, ...state.expenses] }); },
  removeExpense(id) { store.set({ expenses: state.expenses.filter((x) => x.id !== id) }); },

  /* sales */
  addSale(s) { store.set({ sales: [{ id: uid(), ...s }, ...state.sales] }); },
  removeSale(id) { store.set({ sales: state.sales.filter((x) => x.id !== id) }); },

  /* products */
  addProduct(p) { store.set({ products: [{ id: uid(), ...p }, ...state.products] }); },
  updateProduct(id, patch) { store.set({ products: state.products.map((x) => x.id === id ? { ...x, ...patch } : x) }); },
  removeProduct(id) { store.set({ products: state.products.filter((x) => x.id !== id) }); },

  /* prints */
  addPrint(p) { store.set({ prints: [{ id: uid(), ...p }, ...state.prints] }); },
  removePrint(id) { store.set({ prints: state.prints.filter((x) => x.id !== id) }); },

  resetAll() { state = seed(); emit(); },
  wipe() { state = { settings: state.settings, filaments: [], debts: [], expenses: [], sales: [], products: [], prints: [] }; emit(); },

  /* ---- sincronização com a nuvem ---- */
  setSyncHandler(fn) { _syncHandler = fn; },
  // aplica estado vindo da nuvem sem reempurrar (evita loop)
  applyRemote(data) {
    _applyingRemote = true;
    state = { ...EMPTY, ...(data || {}) };
    persist();
    listeners.forEach((l) => l());
    _applyingRemote = false;
  },
};

function useStore() {
  return React.useSyncExternalStore(store.subscribe, store.get);
}

/* ---------- formatting + finance helpers ---------- */
const fmt = {
  brl(n, dec = 2) {
    if (n == null || isNaN(n)) n = 0;
    return 'R$ ' + Number(n).toLocaleString('pt-BR', { minimumFractionDigits: dec, maximumFractionDigits: dec });
  },
  brl0(n) { return fmt.brl(n, 0); },
  num(n, dec = 0) { return Number(n || 0).toLocaleString('pt-BR', { minimumFractionDigits: dec, maximumFractionDigits: dec }); },
  date(iso) {
    if (!iso) return '';
    const [y, m, d] = iso.split('-');
    return `${d}/${m}`;
  },
  dateFull(iso) {
    if (!iso) return '';
    const [y, m, d] = iso.split('-');
    return `${d}/${m}/${y}`;
  },
  pct(n) { return Math.round(n) + '%'; },
  hm(min) {
    const h = Math.floor(min / 60), m = Math.round(min % 60);
    return h > 0 ? `${h}h${m > 0 ? ' ' + m + 'min' : ''}` : `${m}min`;
  },
};

/* Compute full cost breakdown for a print job */
function computeCost(input, settings) {
  const { grams = 0, costPerKg = 0, printTimeMin = 0, packaging = 0, margin = 0, failRate = 0, marketplaceFee = 0, extraCost = 0 } = input;
  const hours = printTimeMin / 60;
  const filament = (grams / 1000) * costPerKg;
  const energy = (settings.powerWatts / 1000) * hours * settings.energyCostKwh;
  const labor = hours * settings.laborPerHour;
  const depreciation = (settings.printerCost / settings.printerLifeHours) * hours;
  const baseCost = filament + energy + labor + depreciation + packaging + extraCost;
  const withFail = baseCost * (1 + failRate / 100);
  const withMargin = withFail * (1 + margin / 100);
  // final price grossed up so marketplace fee leaves `withMargin` net
  const finalPrice = marketplaceFee > 0 ? withMargin / (1 - marketplaceFee / 100) : withMargin;
  const feeAmount = finalPrice - withMargin;
  const profit = withMargin - withFail;
  return { hours, filament, energy, labor, depreciation, packaging, extraCost, baseCost, withFail, failAmount: withFail - baseCost, withMargin, finalPrice, feeAmount, profit, marginPct: margin };
}

/* month helpers */
function isThisMonth(iso, ref = new Date()) {
  if (!iso) return false;
  const [y, m] = iso.split('-').map(Number);
  return y === ref.getFullYear() && m === ref.getMonth() + 1;
}

Object.assign(window, { useStore, store, fmt, computeCost, isThisMonth, uid, today });
