/* ============================================================
   App — composition layer for FreeM0ney v2 dashboard
   ============================================================ */
const { useState: useStateApp, useEffect: useEffectApp, useMemo: useMemoApp } = React;

// Default accent palette (overridden by Tweaks panel via __edit_mode_set_keys)
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "palette": ["#27f0a3", "#4fe4ff", "#ff4d8d"]
} /*EDITMODE-END*/;

const PALETTE_OPTIONS = [
['#27f0a3', '#4fe4ff', '#ff4d8d'], // teal · cyan · pink (default)
['#4fe4ff', '#7c5cff', '#27f0a3'], // cyan · violet · teal
['#ffb648', '#ff4d8d', '#4fe4ff'], // amber · pink · cyan
['#d4af37', '#caa86b', '#27f0a3'] // gold · bronze · teal
];

function applyPalette([a, b, c]) {
  const r = document.documentElement.style;
  r.setProperty('--acc', a);
  r.setProperty('--acc-2', b);
  r.setProperty('--acc-3', c);
}
window.__fm_applyPalette = applyPalette;

// ── User preferences (localStorage fm_prefs) ─────────────
const FM_PREFS_KEY = 'fm_prefs';
function _getPrefs() {
  try { return JSON.parse(localStorage.getItem(FM_PREFS_KEY) || '{}'); } catch(_) { return {}; }
}
function _setPrefs(patch) {
  const p = { ..._getPrefs(), ...patch };
  localStorage.setItem(FM_PREFS_KEY, JSON.stringify(p));
  return p;
}
window.__fm_getPrefs = _getPrefs;
window.__fm_setPrefs = _setPrefs;

// ── Web Audio beep alert ─────────────────────────────────
// Double beep: 880Hz + 1100Hz, fired on new surebet/notification
function _playBeep() {
  try {
    const prefs = _getPrefs();
    if (prefs.soundEnabled === false) return; // disabled by user
    const vol = typeof prefs.soundVolume === 'number' ? prefs.soundVolume : 0.15;
    const ctx = new (window.AudioContext || window.webkitAudioContext)();
    [[880, 0], [1100, 0.18]].forEach(([freq, delay]) => {
      const o = ctx.createOscillator(), g = ctx.createGain();
      o.connect(g); g.connect(ctx.destination);
      o.frequency.value = freq; o.type = 'sine';
      g.gain.setValueAtTime(vol, ctx.currentTime + delay);
      g.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + delay + 0.22);
      o.start(ctx.currentTime + delay);
      o.stop(ctx.currentTime + delay + 0.22);
    });
    setTimeout(() => { try { ctx.close(); } catch (_) {} }, 800);
  } catch (_) {}
}
window.__fm_playBeep = _playBeep;

function App() {
  const [tweaks, setTweak] = window.useTweaks ? window.useTweaks(TWEAK_DEFAULTS) : [TWEAK_DEFAULTS, () => {}];

  useEffectApp(() => {applyPalette(tweaks.palette || TWEAK_DEFAULTS.palette);}, [tweaks.palette]);

  // Check ?tab= URL param on load (payment.html redirect → /?tab=payment)
  const _initTab = (() => {
    try { const p = new URLSearchParams(window.location.search); return p.get('tab') || 'dashboard'; } catch(e) { return 'dashboard'; }
  })();
  const [active, setActive] = useStateApp(_initTab);
  // Expose nav for popovers; emit page-change so server can track active view
  useEffectApp(() => {
    window.__fm_nav = (page) => {
      setActive(page);
      if (window.__fm_socket) window.__fm_socket.emit('page-change', { page });
    };
    return () => { delete window.__fm_nav; };
  }, []);
  const [pinned, setPinned] = useStateApp(false);
  const [dataMode, setDataMode] = useStateApp('live');
  const [paused, setPaused] = useStateApp(false);
  const _frozenSb = React.useRef(null); // snapshot when paused

  // Freeze surebet list on pause (don't clear — keep showing last known state)
  const handlePause = React.useCallback((p) => {
    if (p) _frozenSb.current = [...(window.__fm_currentSurebets ? window.__fm_currentSurebets() : sbData)];
    else _frozenSb.current = null;
    setPaused(p);
  }, [sbData]);
  const [search, setSearch] = useStateApp('');
  const [hidden, setHidden] = useStateApp(new Set());

  // Separate filter state per mode — live and prematch are independent
  const _emptyFilters = () => ({ sports: new Set(), books: new Set(), roiMin: 0, roiMax: 100, sort: 'ROI ↓' });
  const [liveFilters, setLiveFilters] = useStateApp(_emptyFilters());
  const [prematchFilters, setPrematchFilters] = useStateApp(_emptyFilters());

  // Active filters = whichever mode is current
  const filters = dataMode === 'prematch' ? prematchFilters : liveFilters;

  // Use ref so handleSetFilters is stable but always sees latest mode/state
  const _dataModeRef = React.useRef(dataMode);
  const _liveFiltersRef = React.useRef(liveFilters);
  const _prematchFiltersRef = React.useRef(prematchFilters);
  _dataModeRef.current = dataMode;
  _liveFiltersRef.current = liveFilters;
  _prematchFiltersRef.current = prematchFilters;

  const _filterSaveTimer = React.useRef(null);
  const handleSetFilters = React.useCallback((updater) => {
    const mode = _dataModeRef.current;
    const setter = mode === 'prematch' ? setPrematchFilters : setLiveFilters;
    setter(prev => {
      const next = typeof updater === 'function' ? updater(prev) : updater;
      if (_filterSaveTimer.current) clearTimeout(_filterSaveTimer.current);
      _filterSaveTimer.current = setTimeout(() => {
        if (window.__fm_savePreferences) {
          const toObj = (f) => ({
            sports: [...f.sports],
            bookmakers: [...f.books],
            minRoi: f.roiMin,
            maxRoi: f.roiMax,
            sortBy: f.sort === 'ROI ↑' ? 'roi_asc' : f.sort === 'Profit ↓' ? 'profit_desc' : f.sort === 'Newest' ? 'newest' : f.sort === 'League' ? 'league' : f.sort === 'Bookmaker' ? 'bookmaker' : 'roi_desc',
          });
          window.__fm_savePreferences({
            filtersLive: mode === 'live' ? toObj(next) : toObj(_liveFiltersRef.current),
            filtersPrematch: mode === 'prematch' ? toObj(next) : toObj(_prematchFiltersRef.current),
          });
        }
      }, 500);
      return next;
    });
  }, []); // stable — reads mode via ref

  const _parseFilters = (f) => ({
    sports: new Set(f.sports || []),
    books: new Set(f.bookmakers || []),
    roiMin: f.minRoi ?? 0,
    roiMax: f.maxRoi ?? 100,
    sort: f.sortBy === 'roi_asc' ? 'ROI ↑' : f.sortBy === 'profit_desc' ? 'Profit ↓' : f.sortBy === 'newest' ? 'Newest' : f.sortBy === 'league' ? 'League' : f.sortBy === 'bookmaker' ? 'Bookmaker' : 'ROI ↓',
  });

  // Restore filters from server when api-connector calls loadPreferences()
  useEffectApp(() => {
    window.__fm_applyPreferences = (prefs) => {
      if (!prefs) return;
      // Support both old format (prefs.filters) and new (prefs.filtersLive / prefs.filtersPrematch)
      if (prefs.filtersLive) setLiveFilters(_parseFilters(prefs.filtersLive));
      else if (prefs.filters) setLiveFilters(_parseFilters(prefs.filters));
      if (prefs.filtersPrematch) setPrematchFilters(_parseFilters(prefs.filtersPrematch));
    };
    return () => { delete window.__fm_applyPreferences; };
  }, []);

  const [filterOpen, setFilterOpen] = useStateApp(false);
  const [settingsOpen, setSettingsOpen] = useStateApp(false);

  // Stable hide handler — useCallback prevents new ref on every render,
  // which would break React.memo on SurebetCard and cause full re-renders.
  const handleHide = React.useCallback((id) => {
    setHidden((h) => new Set([...h, id]));
    if (window.__fm_hideSurebet) window.__fm_hideSurebet(id);
  }, []);

  // Live surebet state — updated by api-connector.js via window.__fm_setSurebets
  const [sbData, setSbData] = useStateApp(window.SUREBETS || []);
  useEffectApp(() => {
    window.__fm_setSurebets = setSbData;
    // Flush any data that arrived before React mounted (api-connector loaded first)
    if (window.__fm_currentSurebets) {
      const buffered = window.__fm_currentSurebets();
      if (buffered && buffered.length) setSbData([...buffered]);
    }
    return () => { delete window.__fm_setSurebets; };
  }, []);

  // Wire data mode toggle so api-connector knows which feed to show
  const handleDataMode = (mode) => {
    setDataMode(mode);
    if (window.__fm_setDataMode) window.__fm_setDataMode(mode);
  };

  const surebets = useMemoApp(() => {
    const src = paused ? (_frozenSb.current || sbData) : sbData;
    let out = src.filter((sb) => !hidden.has(sb.id));
    // Filter by live/prematch mode
    // live: true → live tab; live: false/undefined → prematch tab (falsy = prematch)
    if (dataMode === 'live') out = out.filter((sb) => sb.live === true);
    else if (dataMode === 'prematch') out = out.filter((sb) => !sb.live);
    if (filters.sports.size) out = out.filter((sb) => filters.sports.has(sb.sport));
    // Deselecting a bookmaker hides ALL surebets involving it — must use every()
    if (filters.books.size) out = out.filter((sb) => sb.selections.every((s) => filters.books.has(s.book)));
    out = out.filter((sb) => sb.roi >= filters.roiMin && sb.roi <= filters.roiMax);
    // Dedup identical-content surebets (same match+market+books+odds, different id)
    {
      const _seen = new Set();
      out = out.filter((sb) => {
        const k = [sb.home, sb.away, sb.market || sb.type,
          (sb.selections || []).map((s) => s.book + ':' + s.pick + '@' + s.odds).sort().join('|')].join('~');
        if (_seen.has(k)) return false;
        _seen.add(k);
        return true;
      });
    }
    if (search.trim()) {
      const q = search.toLowerCase();
      out = out.filter((sb) =>
      sb.home.toLowerCase().includes(q) ||
      sb.away.toLowerCase().includes(q) ||
      sb.league.toLowerCase().includes(q) ||
      sb.selections.some((s) => s.book.toLowerCase().includes(q))
      );
    }
    switch (filters.sort) {
      case 'ROI ↓':out.sort((a, b) => b.roi - a.roi);break;
      case 'ROI ↑':out.sort((a, b) => a.roi - b.roi);break;
      case 'Profit ↓':out.sort((a, b) => b.profit - a.profit);break;
      case 'Newest':
        out.sort((a, b) => {
          const ta = a.startTime ? new Date(a.startTime).getTime() : Infinity;
          const tb = b.startTime ? new Date(b.startTime).getTime() : Infinity;
          return ta - tb;
        });
        break;
      case 'League':out.sort((a, b) => a.league.localeCompare(b.league));break;
      case 'Bookmaker':out.sort((a, b) => a.selections[0].book.localeCompare(b.selections[0].book));break;
    }
    return out;
  }, [sbData, hidden, liveFilters, prematchFilters, search, paused, dataMode]); // _frozenSb is a ref, not reactive

  // Sound alert: only when NOT paused and visible (filtered) count increases
  const _prevSbLen = React.useRef(0);
  useEffectApp(() => {
    if (!paused && surebets.length > _prevSbLen.current && _prevSbLen.current > 0) {
      _playBeep();
    }
    _prevSbLen.current = surebets.length;
  }, [surebets, paused]);

  const isMobile = window.__fm_useIsMobile ? window.__fm_useIsMobile() : React.useState(window.innerWidth < 768)[0];

  return (
    <div style={{ display: 'flex', minHeight: '100vh' }}>
      <Sidebar
        active={active}
        onNav={setActive}
        pinned={pinned}
        onTogglePin={() => setPinned((p) => !p)} />


      <main style={{ flex: 1, minWidth: 0, display: 'flex', flexDirection: 'column', paddingBottom: isMobile ? 58 : 0 }}>
        <Topbar
          onSearch={setSearch}
          dataMode={dataMode} setDataMode={handleDataMode}
          paused={paused} setPaused={handlePause}
          active={active} />
        

        {active === 'payment' && window.SubscriptionView ?
        <window.SubscriptionView /> :
        active === 'smartbets' && window.SmartBetsView ?
        <window.SmartBetsView /> :
        active === 'analytics' && window.AnalyticsView ?
        <window.AnalyticsView /> :
        active === 'profile' && window.ProfileView ?
        <window.ProfileView /> :
        active === 'tips' && window.TipsView ?
        <window.TipsView /> :
        active === 'calc' && window.CalcView ?
        <window.CalcView /> :
        active === 'about' && window.AboutView ?
        <window.AboutView /> :
        active === 'contact' && window.ContactView ?
        <window.ContactView /> :
        active === 'admin' && window.AdminView ?
        <window.AdminView /> :

        <div className="dash-grid" style={{
          padding: isMobile ? '14px 12px' : '22px 56px',
          display: 'grid',
          gap: isMobile ? 12 : 18,
          alignItems: 'start'
        }}>
          {/* center column */}
          <div style={{ display: 'flex', flexDirection: 'column', gap: 18, minWidth: 0 }}>
            {/* Surebet feed header */}
            <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '0 4px' }}>
              <div style={{ display: 'flex', alignItems: 'baseline', gap: 14 }}>
                <h1 style={{ fontSize: 22, fontWeight: 700, margin: 0, letterSpacing: '-0.01em' }}>
                  Live Surebet Feed
                  <span className="mono" style={{ marginLeft: 12, fontSize: 11, color: 'var(--fg-dim)', fontWeight: 500, letterSpacing: '0.08em' }}>
                    {surebets.length} active · {dataMode.toUpperCase()}
                  </span>
                </h1>
              </div>
              <div style={{ display: 'flex', gap: 8 }}>
                <button
                  onClick={() => setSettingsOpen(true)}
                  className="mono"
                  id="openSettingsIcon"
                  style={{
                    padding: '7px 12px', borderRadius: 10,
                    background: 'rgba(8,13,24,0.55)', border: '1px solid var(--bd)',
                    color: 'var(--fg-muted)', cursor: 'pointer', fontSize: 11, letterSpacing: '0.06em', fontWeight: 600
                  }}>⚙ SETTINGS</button>
                <button
                  onClick={() => setFilterOpen((o) => !o)}
                  className="mono"
                  style={{
                    padding: '7px 12px', borderRadius: 10,
                    background: filterOpen ?
                    'linear-gradient(135deg, color-mix(in srgb, var(--acc) 40%, transparent), transparent)' :
                    'linear-gradient(135deg, color-mix(in srgb, var(--acc) 20%, transparent), transparent)',
                    border: '1px solid color-mix(in srgb, var(--acc) 45%, transparent)',
                    color: 'var(--acc)', cursor: 'pointer', fontSize: 11, letterSpacing: '0.06em', fontWeight: 700,
                    textShadow: '0 0 10px color-mix(in srgb, var(--acc) 45%, transparent)',
                    display: 'inline-flex', alignItems: 'center', gap: 6
                  }}>
                  <span>{filterOpen ? '× HIDE FILTERS' : '+ FILTERS'}</span>
                  {filters.sports.size + filters.books.size > 0 &&
                  <span className="mono" style={{ padding: '0 6px', minWidth: 16, height: 16, borderRadius: 999, background: 'var(--acc)', color: '#06140f', fontSize: 9, fontWeight: 800, display: 'inline-grid', placeItems: 'center' }}>{filters.sports.size + filters.books.size}</span>
                  }
                </button>
              </div>
            </div>

            {/* surebet grid */}
            <div className="sb-grid" style={{
              display: 'grid',
              gridTemplateColumns: isMobile ? '1fr' : 'repeat(3, minmax(0, 1fr))',
              gap: isMobile ? 10 : 18
            }}>
              {surebets.length === 0 ?
              <div style={{ gridColumn: '1 / -1', display: 'flex', justifyContent: 'center', alignItems: 'center', minHeight: 420, position: 'relative' }}>
                <img
                  src="/img/no-surebets.png"
                  alt=""
                  onError={e => { e.currentTarget.style.display = 'none'; e.currentTarget.nextSibling.style.display = 'flex'; }}
                  style={{
                    maxHeight: 460,
                    maxWidth: '100%',
                    objectFit: 'contain',
                    /* CSS sharpen */
                    filter: 'contrast(1.08) saturate(1.12)',
                    imageRendering: 'crisp-edges',
                    WebkitFilter: 'contrast(1.08) saturate(1.12)',
                  }}
                />
                {/* fallback if image not found */}
                <div style={{ display: 'none', flexDirection: 'column', alignItems: 'center', gap: 18 }}>
                  <div style={{
                    padding: '10px 20px', borderRadius: 10,
                    background: 'rgba(0,220,150,0.12)', border: '1px solid rgba(0,220,150,0.35)',
                    fontFamily: 'var(--font-mono)', fontSize: 12, letterSpacing: '0.08em',
                    color: '#27f0a3', textTransform: 'uppercase'
                  }}>Live Surebet Feed: Scanning...</div>
                  <div style={{
                    padding: '14px 28px', borderRadius: 10,
                    background: 'rgba(220,40,40,0.18)', border: '1px solid rgba(220,40,40,0.45)',
                    fontFamily: 'var(--font-mono)', fontSize: 15, fontWeight: 700, letterSpacing: '0.1em',
                    color: '#ff4444', textTransform: 'uppercase'
                  }}>No Active Surebets</div>
                  <div style={{
                    padding: '10px 20px', borderRadius: 10,
                    background: 'rgba(0,180,200,0.12)', border: '1px solid rgba(0,180,200,0.35)',
                    fontFamily: 'var(--font-mono)', fontSize: 12, letterSpacing: '0.08em',
                    color: 'var(--fg-muted)', textTransform: 'uppercase'
                  }}>Try refreshing in 5s...</div>
                </div>
              </div> :
              surebets.map((sb) =>
              <SurebetCard key={sb.id} sb={sb} onHide={handleHide} />
              )}
            </div>
          </div>
        </div>
        }
      </main>

      {/* Filter modal */}
      {filterOpen && (
        <div onClick={() => setFilterOpen(false)} style={{
          position: 'fixed', inset: 0, zIndex: 100,
          background: 'rgba(2,5,12,0.55)',
          backdropFilter: 'blur(8px)', WebkitBackdropFilter: 'blur(8px)',
          display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 20,
        }}>
          <div onClick={(e) => e.stopPropagation()} style={{
            width: 460, maxWidth: '100%', maxHeight: '92vh', overflowY: 'auto',
            borderRadius: 22,
            background: 'rgba(14,22,40,0.32)',
            backdropFilter: 'blur(28px) saturate(1.5)', WebkitBackdropFilter: 'blur(28px) saturate(1.5)',
            border: '1px solid color-mix(in srgb, var(--acc) 22%, rgba(180,210,255,0.18))',
            boxShadow: '0 38px 90px -18px rgba(0,0,0,0.85), 0 0 50px -14px color-mix(in srgb, var(--acc) 28%, transparent), inset 0 1.6px 0 rgba(255,255,255,0.30)',
            color: 'var(--fg)',
          }}>
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '16px 20px', borderBottom: '1px solid var(--bd)' }}>
              <h3 style={{ fontFamily: 'var(--font-display)', fontSize: 17, fontWeight: 600, margin: 0 }}>⏷ Filters</h3>
              <button onClick={() => setFilterOpen(false)} style={{
                background: 'rgba(8,13,24,0.55)', border: '1px solid var(--bd)', color: 'var(--fg-muted)',
                width: 32, height: 32, fontSize: 18, lineHeight: 1, borderRadius: 8, cursor: 'pointer',
              }}>&times;</button>
            </div>
            <div style={{ padding: 16 }}>
              <FilterPanel filters={filters} setFilters={handleSetFilters} />
            </div>
          </div>
        </div>
      )}

      {/* Subscription view portals — overlays mounted always so JS can find them */}
      <div className="sale-popup-overlay" id="salePopup" onClick={(e) => {if (e.target.id === 'salePopup' && window.__fm_closeSalePopup) window.__fm_closeSalePopup();}}>
        <div className="sale-popup">
          <button className="sale-popup-x" onClick={() => window.__fm_closeSalePopup && window.__fm_closeSalePopup()} aria-label="Close">&times;</button>
          <img id="salePopupImg" alt="Sale" style={{ display: 'none' }} />
          <div className="sale-popup-body">
            <div className="sale-popup-title" id="salePopupTitle"></div>
            <div className="sale-popup-text" id="salePopupText"></div>
            <button className="sale-popup-close" onClick={() => window.__fm_closeSalePopup && window.__fm_closeSalePopup()}>OK, đã hiểu!</button>
          </div>
        </div>
      </div>
      <div className="payment-overlay" id="paymentOverlay">
        <div className="payment-modal" id="paymentModal"></div>
      </div>

      {/* Tweaks panel */}
      {window.TweaksPanel &&
      <window.TweaksPanel title="Tweaks">
          <window.TweakSection title="Accent palette">
            <PaletteSwatches
            value={tweaks.palette}
            onChange={(p) => setTweak('palette', p)} />
          
          </window.TweakSection>
        </window.TweaksPanel>
      }

      {/* Floating action buttons (FABs) */}
      <FABs />

      {/* Settings modal */}
      {settingsOpen && <BankrollModal onClose={() => setSettingsOpen(false)} />}
    </div>);

}

function PaletteSwatches({ value, onChange }) {
  const eq = (a, b) => a && b && a[0] === b[0] && a[1] === b[1] && a[2] === b[2];
  return (
    <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: 8 }}>
      {PALETTE_OPTIONS.map((p, i) => {
        const active = eq(p, value);
        return (
          <button key={i} onClick={() => onChange(p)} style={{
            padding: 8, borderRadius: 10,
            background: 'rgba(8,13,24,0.55)',
            border: `1px solid ${active ? p[0] : 'var(--bd)'}`,
            cursor: 'pointer', textAlign: 'left',
            boxShadow: active ? `0 0 0 2px color-mix(in srgb, ${p[0]} 30%, transparent)` : 'none'
          }}>
            <div style={{ display: 'flex', gap: 4, marginBottom: 6 }}>
              {p.map((c, j) =>
              <span key={j} style={{
                flex: 1, height: 26, borderRadius: 6,
                background: c,
                boxShadow: `0 0 12px -2px ${c}, inset 0 1px 0 rgba(255,255,255,0.3)`
              }} />
              )}
            </div>
            <div className="mono" style={{ fontSize: 9.5, color: active ? p[0] : 'var(--fg-dim)', letterSpacing: '0.06em', fontWeight: 700 }}>
              {['TEAL·CYAN·PINK', 'CYAN·VIOLET·TEAL', 'AMBER·PINK·CYAN', 'GOLD·BRONZE·TEAL'][i]}
            </div>
          </button>);

      })}
    </div>);

}

function FABs() {
  const [open, setOpen] = useStateApp(false);
  const _isMob = window.__fm_useIsMobile ? window.__fm_useIsMobile() : false;
  return (
    <>
      <button
        title="Arbitrage Calculator"
        onClick={() => setOpen(true)}
        style={{
          position: 'fixed', bottom: _isMob ? 70 : 24, right: 24, zIndex: 50,
          width: 56, height: 56, borderRadius: '50%',
          background: 'linear-gradient(135deg, var(--acc), color-mix(in srgb, var(--acc) 40%, #0a0510))',
          border: '1px solid color-mix(in srgb, var(--acc) 50%, white)',
          color: '#06140f', cursor: 'pointer',
          boxShadow: '0 12px 30px -8px color-mix(in srgb, var(--acc) 60%, transparent), 0 0 24px -4px var(--acc), inset 0 1px 0 rgba(255,255,255,0.4)',
          display: 'grid', placeItems: 'center', fontSize: 22, fontWeight: 800
        }}>∑</button>
      {open &&
      <div onClick={() => setOpen(false)} style={{
        position: 'fixed', inset: 0, zIndex: 100,
        background: 'rgba(2,5,12,0.74)',
        backdropFilter: 'blur(10px)', WebkitBackdropFilter: 'blur(10px)',
        display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 20
      }}>
          <div onClick={(e) => e.stopPropagation()} style={{
          width: 920, maxWidth: '100%', maxHeight: '92vh', minHeight: _isMob ? '70vh' : undefined, overflowY: 'auto',
          borderRadius: 22,
          background: 'rgba(14,22,40,0.32)',
          backdropFilter: 'blur(28px) saturate(1.5)', WebkitBackdropFilter: 'blur(28px) saturate(1.5)',
          border: '1px solid color-mix(in srgb, var(--acc) 22%, rgba(180,210,255,0.18))',
          boxShadow:
          '0 38px 90px -18px rgba(0,0,0,0.85), ' +
          '0 0 50px -14px color-mix(in srgb, var(--acc) 28%, transparent), ' +
          'inset 0 1.6px 0 rgba(255,255,255,0.30)',
          color: 'var(--fg)'
        }}>
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '16px 20px', borderBottom: '1px solid var(--bd)' }}>
              <h3 style={{ fontFamily: 'var(--font-display)', fontSize: 17, fontWeight: 600, margin: 0 }}>∑ Arbitrage Calculator</h3>
              <button onClick={() => setOpen(false)} style={{
              background: 'rgba(8,13,24,0.55)', border: '1px solid var(--bd)', color: 'var(--fg-muted)',
              width: 32, height: 32, fontSize: 18, lineHeight: 1, borderRadius: 8, cursor: 'pointer'
            }}>&times;</button>
            </div>
            <div style={{ padding: 4 }}>
              {window.CalcView ? <window.CalcView /> : <div style={{ padding: 30, textAlign: 'center', color: 'var(--fg-muted)' }}>Calculator loading…</div>}
            </div>
          </div>
        </div>
      }
    </>);

}

const _SETTINGS_BKS = ['parimatch','1xbet','taptap','stake','raybet','tfgaming','saba','mansion88','sbobet','fbsports','pinnacle','bcgame','polymarket'];
const _SETTINGS_LABELS = { '1xbet':'1xBet','parimatch':'Parimatch','taptap':'TapTap','stake':'Stake','raybet':'RayBet','tfgaming':'TF Gaming','saba':'Saba','mansion88':'Mansion 88','sbobet':'Sbobet','fbsports':'FB Sports','pinnacle':'Pinnacle','bcgame':'BC Game','polymarket':'Polymarket' };
const _CCYS = ['USD','USDT','VND','EUR'];
const _CCY_SYM = { USD:'$', USDT:'₮', VND:'₫', EUR:'€' };

function _getUserId() {
  return (window.__fm_currentUser && window.__fm_currentUser.id) ||
    localStorage.getItem('fm_userId') || 'guest';
}

function _loadSettings() {
  try {
    const key = `fm_settings_${_getUserId()}`;
    const s = JSON.parse(localStorage.getItem(key) || localStorage.getItem('fm_settings') || '{}');
    const bankroll = {};
    const links = {};
    _SETTINGS_BKS.forEach(bk => {
      bankroll[bk] = { amount: s.bankroll?.[bk]?.amount ?? 100, currency: s.bankroll?.[bk]?.currency ?? (bk === 'polymarket' ? 'USDT' : 'USD') };
      links[bk] = s.links?.[bk] ?? '';
    });
    return { bankroll, links };
  } catch { return null; }
}

function BankrollModal({ onClose }) {
  const [tab, setTab] = useStateApp('general');
  const saved0 = _loadSettings();
  const initBR = saved0?.bankroll || Object.fromEntries(_SETTINGS_BKS.map(bk => [bk, { amount: 100, currency: bk === 'polymarket' ? 'USDT' : 'USD' }]));
  const initLinks = saved0?.links || Object.fromEntries(_SETTINGS_BKS.map(bk => [bk, '']));
  const [bankroll, setBankroll] = useStateApp(initBR);
  const [links, setLinks] = useStateApp(initLinks);
  const [saved, setSaved] = useStateApp(false);

  const rates = window.exchangeRates?.rates || { USD:1, USDT:1, VND:25500, EUR:0.92 };
  const totalUSD = _SETTINGS_BKS.reduce((sum, bk) => {
    const { amount, currency } = bankroll[bk];
    return sum + (parseFloat(amount) || 0) / (rates[currency] || 1);
  }, 0);

  const setAmt = (bk, v) => setBankroll(p => ({ ...p, [bk]: { ...p[bk], amount: v } }));
  const setCcy = (bk, v) => setBankroll(p => ({ ...p, [bk]: { ...p[bk], currency: v } }));
  const setLink = (bk, v) => setLinks(p => ({ ...p, [bk]: v }));

  const handleSave = () => {
    localStorage.setItem(`fm_settings_${_getUserId()}`, JSON.stringify({ bankroll, links }));
    window.__fm_bkLinks = links;
    window.__fm_bankroll = bankroll;
    // Persist to server
    const bkRoll = Object.fromEntries(_SETTINGS_BKS.map(bk => [bk, { amount: parseFloat(bankroll[bk].amount) || 100, currency: bankroll[bk].currency }]));
    const tk = localStorage.getItem('fm_token');
    if (tk) {
      fetch('/api/auth/bankroll', { method: 'PUT', headers: { 'Content-Type': 'application/json', Authorization: 'Bearer ' + tk }, body: JSON.stringify({ bankroll: bkRoll }) }).catch(() => {});
    }
    setSaved(true);
    setTimeout(() => { setSaved(false); onClose(); }, 1000);
  };

  const iS = { padding: '6px 10px', borderRadius: 7, background: 'rgba(8,13,24,0.55)', border: '1px solid var(--bd)', color: 'var(--acc)', fontFamily: 'var(--font-mono)', fontSize: 13, fontWeight: 700, textAlign: 'right', outline: 'none', width: 90 };
  const sS = { padding: '5px 6px', borderRadius: 7, background: 'rgba(8,13,24,0.55)', border: '1px solid var(--bd)', color: 'var(--fg-muted)', fontSize: 11, outline: 'none' };
  const glassBox = { width: 540, maxWidth: '100%', maxHeight: '92vh', overflowY: 'auto', borderRadius: 22, background: 'linear-gradient(165deg, rgba(56,76,120,0.50) 0%, rgba(14,22,40,0.92) 100%)', backdropFilter: 'blur(38px) saturate(1.8)', WebkitBackdropFilter: 'blur(38px) saturate(1.8)', border: '1px solid color-mix(in srgb, var(--acc) 28%, rgba(150,190,255,0.16))', boxShadow: '0 38px 90px -18px rgba(0,0,0,0.95), 0 0 50px -14px color-mix(in srgb, var(--acc) 35%, transparent), inset 0 1.6px 0 rgba(255,255,255,0.35)', color: 'var(--fg)' };

  return (
    <div onClick={onClose} style={{ position: 'fixed', inset: 0, zIndex: 100, background: 'rgba(2,5,12,0.74)', backdropFilter: 'blur(10px)', WebkitBackdropFilter: 'blur(10px)', display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 20 }}>
      <div onClick={(e) => e.stopPropagation()} style={glassBox}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '16px 20px', borderBottom: '1px solid var(--bd)' }}>
          <h3 style={{ fontFamily: 'var(--font-display)', fontSize: 17, fontWeight: 600, margin: 0 }}>⚙ Settings</h3>
          <button onClick={onClose} style={{ background: 'rgba(8,13,24,0.55)', border: '1px solid var(--bd)', color: 'var(--fg-muted)', width: 32, height: 32, fontSize: 18, lineHeight: 1, borderRadius: 8, cursor: 'pointer' }}>&times;</button>
        </div>
        <div style={{ display: 'flex', gap: 6, padding: '10px 18px', borderBottom: '1px solid var(--bd)' }}>
          {[{ id: 'general', label: 'General' }, { id: 'bookmakers', label: 'Bookmaker Links' }].map(t =>
            <button key={t.id} onClick={() => setTab(t.id)} className="mono" style={{ padding: '7px 14px', borderRadius: 8, border: 'none', background: tab === t.id ? 'color-mix(in srgb, var(--acc) 16%, transparent)' : 'transparent', color: tab === t.id ? 'var(--acc)' : 'var(--fg-muted)', cursor: 'pointer', fontSize: 11, fontWeight: 700, letterSpacing: '0.08em' }}>{t.label.toUpperCase()}</button>
          )}
        </div>
        <div style={{ padding: 20 }}>
          {tab === 'general' ? (
            <div style={{ display: 'grid', gap: 10 }}>
              <div className="mono" style={{ fontSize: 10, letterSpacing: '0.10em', color: 'var(--fg-muted)', textTransform: 'uppercase', marginBottom: 2 }}>Bankroll · Per Bookmaker</div>
              {_SETTINGS_BKS.map(bk => (
                <div key={bk} style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '8px 12px', borderRadius: 10, background: 'rgba(8,13,24,0.55)', border: '1px solid var(--bd)' }}>
                  <span className="mono" style={{ flex: 1, fontSize: 12, color: 'var(--fg)', letterSpacing: '0.04em', textTransform: 'uppercase' }}>{_SETTINGS_LABELS[bk] || bk}</span>
                  <select value={bankroll[bk].currency} onChange={e => setCcy(bk, e.target.value)} style={sS}>
                    {_CCYS.map(c => <option key={c} value={c}>{_CCY_SYM[c]} {c}</option>)}
                  </select>
                  <input type="number" value={bankroll[bk].amount} min="0" onChange={e => setAmt(bk, e.target.value)} style={iS} />
                </div>
              ))}
              <div className="mono" style={{ display: 'flex', justifyContent: 'space-between', padding: '8px 12px', borderRadius: 10, background: 'color-mix(in srgb, var(--acc) 8%, transparent)', border: '1px solid color-mix(in srgb, var(--acc) 30%, transparent)' }}>
                <span style={{ fontSize: 11, letterSpacing: '0.10em', color: 'var(--fg-muted)', textTransform: 'uppercase' }}>Total (USD equiv.)</span>
                <span style={{ fontSize: 14, fontWeight: 800, color: 'var(--acc)', textShadow: '0 0 12px color-mix(in srgb, var(--acc) 50%, transparent)' }}>${totalUSD.toFixed(0)}</span>
              </div>
            </div>
          ) : (
            <div style={{ display: 'grid', gap: 12 }}>
              <p style={{ color: 'var(--fg-muted)', fontSize: 12.5, margin: 0 }}>Affiliate links cho từng bookmaker.</p>
              {_SETTINGS_BKS.map(bk => (
                <label key={bk}>
                  <span className="mono" style={{ fontSize: 9.5, letterSpacing: '0.10em', color: 'var(--fg-muted)', textTransform: 'uppercase', display: 'block', marginBottom: 4 }}>{_SETTINGS_LABELS[bk] || bk}</span>
                  <input value={links[bk]} onChange={e => setLink(bk, e.target.value)} placeholder={`https://...`} style={{ width: '100%', boxSizing: 'border-box', padding: '10px 12px', borderRadius: 10, background: 'rgba(8,13,24,0.55)', border: '1px solid var(--bd)', color: 'var(--fg)', fontFamily: 'var(--font-mono)', fontSize: 12, outline: 'none' }} />
                </label>
              ))}
            </div>
          )}
          <button onClick={handleSave} className="mono" style={{ width: '100%', marginTop: 18, padding: '13px 16px', border: '1px solid color-mix(in srgb, var(--acc) 70%, white)', borderRadius: 11, background: saved ? 'linear-gradient(135deg,#27f0a3,#4fe4ff)' : 'linear-gradient(135deg, color-mix(in srgb, var(--acc) 92%, white), var(--acc))', color: '#052816', fontSize: 11.5, fontWeight: 800, letterSpacing: '0.14em', textTransform: 'uppercase', cursor: 'pointer', boxShadow: '0 10px 24px -8px color-mix(in srgb, var(--acc) 55%, transparent), inset 0 1px 0 rgba(255,255,255,0.40)' }}>{saved ? '✓ SAVED' : 'Save & Close'}</button>
        </div>
      </div>
    </div>
  );
}

function CalcView() {
  const [displayCcy, setDisplayCcy] = useStateApp('USD');
  const [totalStake, setTotalStake] = useStateApp(100);
  const [bets, setBets] = useStateApp([{ odds: '', stake: '', currency: 'USD' }, { odds: '', stake: '', currency: 'USD' }]);
  const [anchor, setAnchor] = useStateApp({ type: 'total', betIdx: null });
  const [res, setRes] = useStateApp({ payout: 0, profit: 0, roi: 0 });

  const getRates = () => window.exchangeRates?.rates || { USD:1, USDT:1, VND:25500, EUR:0.92 };
  const toBase = (amt, fromCcy, dCcy) => { const r = getRates(); return (amt / (r[fromCcy] || 1)) * (r[dCcy || displayCcy] || 1); };
  const fromBase = (amt, toCcy, dCcy) => { const r = getRates(); return (amt / (r[dCcy || displayCcy] || 1)) * (r[toCcy] || 1); };

  const calcRes = (curBets, dCcy) => {
    let minPayout = Infinity, totalBase = 0;
    curBets.forEach(b => {
      const odds = parseFloat(b.odds) || 0, stake = parseFloat(b.stake) || 0;
      const pb = toBase(odds * stake, b.currency, dCcy);
      const sb = toBase(stake, b.currency, dCcy);
      totalBase += sb;
      if (pb > 0 && pb < minPayout) minPayout = pb;
    });
    const payout = minPayout === Infinity ? 0 : minPayout;
    const profit = payout - totalBase;
    const roi = totalBase > 0 ? (profit / totalBase) * 100 : 0;
    setRes({ payout, profit, roi });
  };

  const distribute = (curBets, total, dCcy) => {
    const probs = curBets.map(b => parseFloat(b.odds) > 0 ? 1 / parseFloat(b.odds) : 0);
    const totalProb = probs.reduce((a, v) => a + v, 0);
    if (!totalProb || !total) return curBets;
    return curBets.map((b, i) => !parseFloat(b.odds) ? b : { ...b, stake: fromBase(total * probs[i] / totalProb, b.currency, dCcy).toFixed(2) });
  };

  const equalize = (curBets, anchorIdx, dCcy) => {
    const a = curBets[anchorIdx];
    if (!a || !parseFloat(a.odds) || !parseFloat(a.stake)) return curBets;
    const target = toBase(parseFloat(a.stake) * parseFloat(a.odds), a.currency, dCcy);
    return curBets.map((b, i) => {
      if (i === anchorIdx || !parseFloat(b.odds)) return b;
      return { ...b, stake: fromBase(target / parseFloat(b.odds), b.currency, dCcy).toFixed(2) };
    });
  };

  const applyBets = (newBets, newAnchor, dCcy, newTotal) => {
    const dc = dCcy || displayCcy;
    const ts = newTotal != null ? newTotal : totalStake;
    let out;
    if (newAnchor.type === 'total') {
      out = distribute(newBets, ts, dc);
    } else {
      out = equalize(newBets, newAnchor.betIdx, dc);
      const tot = out.reduce((s, b) => s + toBase(parseFloat(b.stake) || 0, b.currency, dc), 0);
      setTotalStake(parseFloat(tot.toFixed(2)));
    }
    setBets(out);
    calcRes(out, dc);
  };

  const onOdds = (i, v) => { const nb = bets.map((b, j) => j === i ? { ...b, odds: v } : b); applyBets(nb, anchor); };
  const onStake = (i, v) => { const nb = bets.map((b, j) => j === i ? { ...b, stake: v } : b); const na = { type: 'bet', betIdx: i }; setAnchor(na); applyBets(nb, na); };
  const onBetCcy = (i, v) => { const nb = bets.map((b, j) => j === i ? { ...b, currency: v } : b); applyBets(nb, anchor); };
  const onTotal = (v) => { const t = parseFloat(v) || 0; setTotalStake(t); const na = { type: 'total', betIdx: null }; setAnchor(na); applyBets(bets, na, displayCcy, t); };
  const onDCcy = (v) => { setDisplayCcy(v); applyBets(bets, anchor, v); };
  const addBet = () => { const nb = [...bets, { odds: '', stake: '', currency: displayCcy }]; setBets(nb); };
  const reset = () => { setBets([{ odds:'', stake:'', currency:'USD' }, { odds:'', stake:'', currency:'USD' }]); setAnchor({ type:'total', betIdx:null }); setTotalStake(100); setRes({ payout:0, profit:0, roi:0 }); };

  const sym = _CCY_SYM[displayCcy] || '$';
  const fmt = v => displayCcy === 'VND' ? Math.round(v).toLocaleString() : v.toFixed(2);
  const iS = { padding: '8px 10px', borderRadius: 8, background: 'rgba(8,13,24,0.55)', border: '1px solid var(--bd)', color: 'var(--fg)', fontFamily: 'var(--font-mono)', fontSize: 13, width: '100%', boxSizing: 'border-box', outline: 'none' };
  const sS = { padding: '7px 6px', borderRadius: 8, background: 'rgba(8,13,24,0.55)', border: '1px solid var(--bd)', color: 'var(--fg-muted)', fontSize: 11, outline: 'none', width: '100%' };

  return (
    <div style={{ padding: 24 }}>
      <div style={{ display: 'flex', gap: 16, marginBottom: 18, alignItems: 'flex-end' }}>
        <div style={{ flex: 1 }}>
          <div className="mono" style={{ fontSize: 9.5, letterSpacing: '0.10em', color: 'var(--fg-muted)', marginBottom: 5 }}>DISPLAY CURRENCY</div>
          <select value={displayCcy} onChange={e => onDCcy(e.target.value)} style={sS}>
            {_CCYS.map(c => <option key={c} value={c}>{_CCY_SYM[c]} {c}</option>)}
          </select>
        </div>
        <div style={{ flex: 1 }}>
          <div className="mono" style={{ fontSize: 9.5, letterSpacing: '0.10em', color: 'var(--fg-muted)', marginBottom: 5 }}>TOTAL STAKE</div>
          <input type="number" value={totalStake} onChange={e => onTotal(e.target.value)} style={iS} min="0" step="0.01" />
        </div>
      </div>

      <div className="mono" style={{ display: 'grid', gridTemplateColumns: '54px 1fr 1fr 80px 80px', gap: 8, padding: '5px 14px', marginBottom: 4, fontSize: 9, letterSpacing: '0.08em', color: 'var(--fg-dim)' }}>
        <span></span><span>ODDS</span><span>STAKE</span><span>CCY</span><span style={{ textAlign: 'right' }}>PAYOUT</span>
      </div>

      {bets.map((bet, i) => {
        const odds = parseFloat(bet.odds) || 0, stake = parseFloat(bet.stake) || 0;
        const payLocal = odds * stake;
        return (
          <div key={i} style={{ display: 'grid', gridTemplateColumns: '54px 1fr 1fr 80px 80px', gap: 8, alignItems: 'center', padding: '10px 14px', borderRadius: 10, background: 'rgba(8,13,24,0.55)', border: '1px solid var(--bd)', marginBottom: 8 }}>
            <span className="mono" style={{ fontSize: 10, color: 'var(--fg-dim)', fontWeight: 700 }}>BET {i + 1}</span>
            <input type="number" placeholder="Odds" value={bet.odds} onChange={e => onOdds(i, e.target.value)} style={iS} step="0.01" min="1" />
            <input type="number" placeholder="Stake" value={bet.stake} onChange={e => onStake(i, e.target.value)} style={iS} step="0.01" min="0" />
            <select value={bet.currency} onChange={e => onBetCcy(i, e.target.value)} style={sS}>
              {_CCYS.map(c => <option key={c} value={c}>{_CCY_SYM[c]} {c}</option>)}
            </select>
            <div className="mono" style={{ textAlign: 'right', fontSize: 13, fontWeight: 700, color: 'var(--acc)' }}>{_CCY_SYM[bet.currency]}{payLocal > 0 ? payLocal.toFixed(2) : '—'}</div>
          </div>
        );
      })}

      <div style={{ display: 'flex', gap: 8, marginBottom: 24 }}>
        <button onClick={addBet} className="mono" style={{ padding: '9px 16px', borderRadius: 9, background: 'rgba(8,13,24,0.55)', border: '1px solid var(--bd)', color: 'var(--fg-muted)', cursor: 'pointer', fontSize: 11, fontWeight: 700, letterSpacing: '0.06em' }}>+ ADD BET</button>
        <button onClick={reset} className="mono" style={{ padding: '9px 16px', borderRadius: 9, background: 'rgba(8,13,24,0.55)', border: '1px solid var(--bd)', color: 'var(--fg-muted)', cursor: 'pointer', fontSize: 11, fontWeight: 700, letterSpacing: '0.06em' }}>RESET</button>
      </div>

      <div style={{ display: 'grid', gap: 10 }}>
        {[
          { label: 'Guaranteed Payout', value: sym + fmt(res.payout), color: 'var(--fg)' },
          { label: 'Profit', value: (res.profit >= 0 ? '+' : '') + sym + fmt(res.profit), color: res.profit >= 0 ? '#27f0a3' : '#ff4d8d' },
          { label: 'ROI', value: res.roi.toFixed(2) + '%', color: res.roi >= 0 ? '#27f0a3' : '#ff4d8d' },
        ].map(({ label, value, color }) => (
          <div key={label} style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '12px 16px', borderRadius: 11, background: 'rgba(8,13,24,0.55)', border: '1px solid var(--bd)' }}>
            <span style={{ fontSize: 13, color: 'var(--fg-muted)' }}>{label}</span>
            <span className="mono" style={{ fontSize: 16, fontWeight: 800, color }}>{value}</span>
          </div>
        ))}
      </div>

      {window.exchangeRates?.rates?.VND && (
        <div className="mono" style={{ marginTop: 10, fontSize: 10, color: 'var(--fg-dim)', textAlign: 'center' }}>
          Rate: 1 USDT = {(window.exchangeRates.rates.VND).toLocaleString()} VND
        </div>
      )}
    </div>
  );
}

window.CalcView = CalcView;

// Init saved settings on load
(function() {
  const s = _loadSettings();
  if (s) { window.__fm_bkLinks = s.links; window.__fm_bankroll = s.bankroll; }
})();

ReactDOM.createRoot(document.getElementById('root')).render(<App />);