// Demo mode data layer — simulated paper trading via senti-v2-api (/demo/*).
// No real money. The starting balance is seeded from the сом balance the app
// already loads from the dashboard (computePortfolioStats(...).totalKgs), passed
// in as `startSom` — never hardcoded here. State is per-client in KV.

const DEMO_API = 'https://senti-v2-api.ecoholding-perm.workers.dev';

function demoToken() { return localStorage.getItem('senti_token') || ''; }

async function demoFetch(path, { method = 'GET', body } = {}) {
  const headers = { 'Content-Type': 'application/json' };
  const t = demoToken();
  if (t) headers['Authorization'] = `Bearer ${t}`;
  const res = await fetch(DEMO_API + path, { method, headers, body: body ? JSON.stringify(body) : undefined });
  return res.json();
}

// useDemoState(startSom) — loads (and on first access seeds) the demo wallet.
// `startSom` should be the dashboard-loaded сом balance; it is only used the very
// first time, to seed cashSom. Returns { state, loading, error, reload }.
// Build a demo seed from the dashboard portfolio holdings (usePortfolio): сом cash
// from the KGS entry, plus non-crypto holdings as positions (USD currency, KG stocks,
// US stocks). Crypto and the live Binance account are excluded — crypto trades for real.
function buildDemoSeed(holdings, usdKgs) {
  const rate = usdKgs || 88.95;
  let cashSom = 0;
  const positions = [];
  (holdings || []).forEach(h => {
    if (h.source === 'binance') return;                  // real Binance balance, not demo
    const cat = h.category;
    const qty = parseFloat(h.qty) || 0;
    if (qty <= 0 || cat === 'crypto') return;            // crypto is real
    if (cat === 'fiat' && h.symbol === 'KGS') { cashSom += qty; return; }   // сом cash
    const isSom = cat === 'kg';
    const mp = parseFloat(h.manualPrice != null ? h.manualPrice : h.price) || 0;
    const cls = cat === 'stocks' ? 'cfd' : cat === 'fiat' ? 'forex' : cat;  // kg→kg, fiat(non-KGS)→forex
    positions.push({ symbol: h.symbol, name: h.name, cls, qty, avgPriceSom: isSom ? mp : mp * rate });
  });
  return { cashSom, positions };
}

// useDemoState(seed) — seed = { cashSom, positions } from buildDemoSeed. The wallet
// mirrors that seed (via /demo/sync) until the first demo trade, then persists.
function useDemoState(seed) {
  const [state, setState]     = React.useState(null);
  const [loading, setLoading] = React.useState(true);
  const [error, setError]     = React.useState(null);

  const seedKey = seed ? `${Math.round(seed.cashSom || 0)}|${(seed.positions || []).map(p => p.symbol + ':' + p.qty).join(',')}` : '';
  const load = React.useCallback(async () => {
    try {
      const hasSeed = seed && ((seed.cashSom || 0) > 0 || (seed.positions || []).length > 0);
      const d = hasSeed
        ? await demoFetch('/demo/sync', { method: 'POST', body: { cashSom: seed.cashSom, positions: seed.positions } })
        : await demoFetch('/demo/state');
      if (d && !d.error) { setState(d); setError(null); }
      else setError((d && d.error) || 'error');
    } catch (e) { setError(e.message); }
    setLoading(false);
  }, [seedKey]);

  React.useEffect(() => { load(); }, [load]);
  return { state, loading, error, reload: load };
}

// Simulated buy/sell. priceSom = unit price already converted to сом by the caller.
async function demoOrder({ symbol, name, cls, side, qty, priceSom }) {
  return demoFetch('/demo/order', { method: 'POST', body: { symbol, name, cls, side, qty, priceSom } });
}

// Simulated currency exchange. dir: 'buy' = сом→валюта, 'sell' = валюта→сом.
// rate = сом per 1 unit of ccy.
async function demoFx({ ccy, dir, amount, rate }) {
  return demoFetch('/demo/fx', { method: 'POST', body: { ccy, dir, amount, rate } });
}

// Reset the demo wallet back to the dashboard balance.
async function demoReset(startSom = 0) {
  return demoFetch('/demo/reset', { method: 'POST', body: { startSom: Math.round(startSom) } });
}

// Convert the demo wallet history into the app's trade-record shape, so demo
// operations (KG/US stocks, commodities, currency) show up in Orders/Trades history.
function demoHistoryRecords(state) {
  const h = (state && state.history) || [];
  return h.map(e => {
    const isFx = e.type === 'fx';
    const val = e.valueSom != null ? e.valueSom : (isFx ? (e.amount || 0) * (e.rate || 0) : (e.qty || 0) * (e.priceSom || 0));
    return {
      id: 'demo-' + e.ts, recordType: 'order', category: 'demo', time: e.ts,
      symbol: isFx ? e.ccy : e.symbol, side: (isFx ? e.dir : e.side) === 'sell' ? 'Sell' : 'Buy',
      orderType: isFx ? 'Обмен' : 'Демо',
      qty: String(isFx ? e.amount : e.qty), price: String(isFx ? e.rate : e.priceSom),
      value: String(val), cumExecQty: String(isFx ? e.amount : e.qty), cumExecValue: String(val),
      avgPrice: String(isFx ? e.rate : e.priceSom), cumExecFee: '0', status: 'Filled',
      chain: '', demo: true, priceCcy: 'с',
    };
  });
}
async function fetchDemoRecords() {
  try { return demoHistoryRecords(await demoFetch('/demo/state')); }
  catch (e) { return []; }
}

// Raw demo wallet state ({ cashSom, positions, history }) — or null if unavailable.
async function fetchDemoState() {
  try { const d = await demoFetch('/demo/state'); return (d && !d.error) ? d : null; }
  catch (e) { return null; }
}

// Overlay the demo wallet onto the live portfolio holdings so paper trades move the
// displayed balances (home total, Активы, allocation). Non-crypto holdings take their
// quantity from the demo wallet (keeping their live price); сом cash and demo-only
// positions are added; assets sold to zero drop out. Crypto (real Binance) is left
// untouched. Returns a NEW holdings array (input is not mutated).
function demoOverlay(holdings, demo, usdKgs) {
  if (!Array.isArray(holdings)) return holdings || [];
  const active = demo && !demo.error && (
    (Array.isArray(demo.positions) && demo.positions.length) ||
    (Array.isArray(demo.history) && demo.history.length) ||
    parseFloat(demo.cashSom) > 0
  );
  if (!active) return holdings;
  const rate = parseFloat(usdKgs) || 88.95;
  const isCrypto = (h) => h.category === 'crypto' || h.cls === 'crypto' || h.source === 'binance';
  const out = holdings.map(h => ({ ...h }));
  const bySym = {};
  out.forEach(h => { if (!isCrypto(h)) bySym[String(h.symbol).toUpperCase()] = h; });
  const clsMap = { forex: 'cash', kg: 'kg', cfd: 'cfd', comm: 'cfd', stock: 'cfd' };
  const catMap = { forex: 'fiat', kg: 'kg', cfd: 'stocks', comm: 'commodities', stock: 'stocks' };
  const seen = new Set();
  (demo.positions || []).forEach(p => {
    const sym = String(p.symbol || '').toUpperCase(); if (!sym) return;
    seen.add(sym);
    const qty = parseFloat(p.qty) || 0;
    const ex = bySym[sym];
    if (ex) { ex.qty = qty; ex.source = ex.source || 'demo'; }
    else out.push({
      id: 'demo-' + sym, symbol: sym, name: p.name || sym,
      cls: clsMap[p.cls] || p.cls || 'other', category: catMap[p.cls] || 'other',
      price: (parseFloat(p.avgPriceSom) || 0) / rate, ccy: '$', change: 0, qty, spark: [], source: 'demo',
    });
  });
  // Non-crypto holdings the demo no longer holds (sold to zero) — except сом cash.
  out.forEach(h => { if (!isCrypto(h) && String(h.symbol).toUpperCase() !== 'KGS' && !seen.has(String(h.symbol).toUpperCase())) h.qty = 0; });
  // сом cash (valued at 1/rate USD so it counts toward the total).
  const cashSom = parseFloat(demo.cashSom) || 0;
  const kgs = bySym['KGS'];
  if (kgs) { kgs.qty = cashSom; kgs.price = 1 / rate; kgs.ccy = 'с'; kgs.source = 'demo'; }
  else out.push({ id: 'demo-KGS', symbol: 'KGS', name: 'Сом', cls: 'cash', category: 'fiat', price: 1 / rate, ccy: 'с', change: 0, qty: cashSom, spark: [], source: 'demo' });
  // Drop zeroed non-crypto holdings.
  return out.filter(h => isCrypto(h) || (parseFloat(h.qty) || 0) > 0);
}

Object.assign(window, { useDemoState, buildDemoSeed, demoOrder, demoFx, demoReset, demoHistoryRecords, fetchDemoRecords, fetchDemoState, demoOverlay, DEMO_API });
