// Header + routing + day/night theme.
const { useState: aS, useEffect: aE, useMemo: aM, useRef: aR } = React;

// Inject Google Analytics (gtag.js) once, after the overview API tells us
// which property to use. GA4 enhanced measurement picks up SPA history
// changes automatically, so we don't manually emit page_view events.
function installGoogleAnalytics(id) {
  if (!id || window.GA_INSTALLED) return;
  window.GA_INSTALLED = true;
  const s = document.createElement('script');
  s.async = true;
  s.src = 'https://www.googletagmanager.com/gtag/js?id=' + encodeURIComponent(id);
  document.head.appendChild(s);
  window.dataLayer = window.dataLayer || [];
  window.gtag = function () { window.dataLayer.push(arguments); };
  window.gtag('js', new Date());
  window.gtag('config', id);
}

function parseRoute() {
  // Support legacy #/… links by folding them onto the real path.
  if (location.hash.startsWith('#/')) {
    history.replaceState({}, '', location.hash.slice(1));
  }
  const [a, b] = location.pathname.replace(/^\/+|\/+$/g, '').split('/');
  if (a === 'reporter' && b) return { view: 'reporters', kind: 'reporter', addr: decodeURIComponent(b) };
  if (a === 'selector' && b) return { view: 'selectors', kind: 'selector', addr: decodeURIComponent(b) };
  if (a === 'validator' && b) return { view: 'validators', kind: 'validator', addr: decodeURIComponent(b) };
  if (['selectors', 'txs', 'reports', 'disputes', 'bridge', 'validators'].includes(a)) return { view: a };
  return { view: 'reporters' };
}

function Header({ route, navigate, overview }) {
  const [query, setQuery] = aS('');
  const [open, setOpen] = aS(false);
  const [results, setResults] = aS([]);
  const o = overview || {};
  aE(() => {
    if (query.trim().length < 2) { setResults([]); return; }
    let alive = true;
    const t = setTimeout(() => {
      api('/api/search?q=' + encodeURIComponent(query.trim()))
        .then((r) => alive && setResults(r)).catch(() => alive && setResults([]));
    }, 220);
    return () => { alive = false; clearTimeout(t); };
  }, [query]);
  aE(() => {
    const onKey = (e) => {
      if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'k') {
        e.preventDefault();
        document.querySelector('.hdr-search input')?.focus();
      }
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, []);
  const tab = (k) => route.view === k && !route.kind;

  return (
    <header className="hdr">
      <div className="hdr-top">
        <a className="brand" {...navLink(navigate, 'reporters')}>
          <img src="/icons/trb.png" alt="Tellor" width="32" height="32" className="brand-mark" />
          <div>
            <div className="brand-name">Tellor Layer</div>
            <div className="brand-sub muted">Reporter Dashboard</div>
          </div>
        </a>
        <div className="hdr-search">
          <SearchIcon />
          <input value={query} onFocus={() => setOpen(true)} onBlur={() => setTimeout(() => setOpen(false), 200)}
            onChange={(e) => setQuery(e.target.value)}
            onKeyDown={(e) => {
              if (e.key !== 'Enter') return;
              // Resolve the first matching result, or — if the typed string
              // looks like a complete address — navigate directly even
              // without a DB hit.
              const m = results[0];
              const t = query.trim();
              if (m && m.type === 'reporter' && m.addr) { setQuery(''); setOpen(false); navigate('reporter/' + m.addr); }
              else if (m && m.type === 'selector' && m.addr) { setQuery(''); setOpen(false); navigate('selector/' + m.addr); }
              else if (m && m.type === 'validator' && m.addr) { setQuery(''); setOpen(false); navigate('validator/' + m.addr); }
              else if (m && m.type === 'tx' && m.hash && window.EXPLORER) { window.open(window.EXPLORER + m.hash, '_blank'); }
              else if (/^tellorvaloper1[0-9a-z]{30,}$/.test(t)) { setQuery(''); setOpen(false); navigate('validator/' + t); }
              else if (/^tellor1[0-9a-z]{30,}$/.test(t)) { setQuery(''); setOpen(false); navigate('selector/' + t); }
            }}
            placeholder="Search reporter, selector, validator or tx hash…" />
          <kbd>⌘K</kbd>
          {open && results.length > 0 && (
            <div className="search-results">
              {results.map((m, i) => {
                const link = m.type === 'reporter' ? navLink(navigate, 'reporter/' + m.addr)
                  : m.type === 'selector' ? navLink(navigate, 'selector/' + m.addr)
                  : m.type === 'validator' ? navLink(navigate, 'validator/' + m.addr)
                  : m.type === 'tx' && window.EXPLORER
                    ? { href: window.EXPLORER + m.hash, target: '_blank', rel: 'noopener' }
                    : { href: '#' };
                return (
                  <a key={i} className="sr-row" href={link.href}
                    target={link.target} rel={link.rel}
                    // Keep focus on the input so onBlur doesn't fire and
                    // unmount this <a> before the click handler runs.
                    onMouseDown={(e) => e.preventDefault()}
                    onClick={(e) => {
                      if (link.onClick) link.onClick(e);
                      setQuery('');
                      setOpen(false);
                    }}>
                    <span className={'sr-tag tag-' + m.type}>{m.type}</span>
                    {m.type === 'tx' && <span className="sr-glyph">⛓</span>}
                    <span className="sr-text">
                      <span className={'sr-l' + (m.type === 'tx' ? ' mono' : '')}>
                        {m.type === 'tx' ? m.label.slice(0, 26) + '…' : m.label}</span>
                      <span className="sr-s muted mono">{(m.addr || m.hash || '').slice(0, 44)}</span>
                    </span>
                  </a>
                );
              })}
            </div>
          )}
        </div>
        <div className="hdr-right">
          <div className="live-pill">
            <span className="live-dot" /><span className="muted small">Live</span>
            <span className="small mono">{fmt(o.current_height)}</span>
          </div>
        </div>
      </div>

      <div className="stat-row">
        <StatCard label="Chain height" value={fmt(o.current_height)} sub={ago(o.current_time)} />
        <StatCard label="Total reporting power" value={compact(o.total_power)} sub="across all reporters" spark={o.spark_power} />
        <StatCard label="Active reporters" value={fmt(o.reporters)}
          sub={`${o.active || 0} active · ${o.jailed || 0} jailed`} />
        <StatCard label="Selectors" value={fmt(o.selectors)} sub="delegating stake" spark={o.spark_selectors} />
      </div>

      <nav className="tabs">
        {[['reporters', 'Reporters', o.reporters], ['reports', 'Reports', null], ['selectors', 'Selectors', o.selectors], ['validators', 'Validators', null], ['bridge', 'Bridge', null], ['disputes', 'Disputes', null], ['txs', 'Transactions', o.tx_events]].map(([k, l, n]) => (
          <a key={k} className={'tab ' + (tab(k) ? 'active' : '')} {...navLink(navigate, k)}>
            {l}{n != null && <span className="tab-count">{Number(n || 0).toLocaleString()}</span>}
          </a>
        ))}
      </nav>
    </header>
  );
}

function App() {
  const [mode, setMode] = useThemeMode();
  const [route, setRoute] = aS(parseRoute());
  const [boot, setBoot] = aS({ loading: true, overview: null, error: null });

  aE(() => {
    const p = THEME_MODES[mode] || THEME_MODES.night;
    document.body.dataset.theme = p.theme;
    document.body.style.setProperty('--accent', p.accent);
  }, [mode]);

  aE(() => {
    const onPop = () => setRoute(parseRoute());
    window.addEventListener('popstate', onPop);
    return () => window.removeEventListener('popstate', onPop);
  }, []);

  const applyOverview = (ov) => {
    window.EXPLORER = ov.explorer_tx_url || '';
    window.TRB_PRICE = Number(ov.trb_price_usd) || 0;
    installGoogleAnalytics(ov.ga_id);
  };

  const load = () => Promise.all([api('/api/overview'), api('/api/monikers').catch(() => ({}))])
    .then(([ov, mon]) => {
      // /api/monikers now returns { reporters, validators: { byOper, byAcct } }.
      // window.MON keeps the flat reporter-address -> moniker shape used
      // everywhere; window.VAL_MON holds the validator maps so AddressBlock
      // can colour-code valoper-addressed names differently.
      window.MON = (mon && mon.reporters) || mon || {};
      window.VAL_MON = (mon && mon.validators) || { byOper: {}, byAcct: {} };
      applyOverview(ov);
      setBoot({ loading: false, overview: ov, error: null });
    })
    .catch((e) => setBoot({ loading: false, overview: null, error: String(e) }));

  aE(() => {
    load();
    const id = setInterval(() => {
      api('/api/overview').then((ov) => {
        applyOverview(ov);
        setBoot((b) => ({ ...b, overview: ov }));
      }).catch(() => {});
    }, 20000);
    return () => clearInterval(id);
  }, []);

  const navigate = (path) => {
    const next = '/' + path;
    if (location.pathname !== next) history.pushState({}, '', next);
    setRoute(parseRoute());
    window.scrollTo(0, 0);
  };

  if (boot.loading) return <div className="boot"><span className="spin" />Loading Tellor Layer…</div>;
  if (boot.error) return <div className="boot">Could not reach indexer: {boot.error}</div>;

  return (
    <div className="app">
      <ChartDefs />
      <Header route={route} navigate={navigate} overview={boot.overview} />
      <main className="main">
        {route.kind === 'reporter' ? <ReporterDetail addr={route.addr} navigate={navigate} />
          : route.kind === 'selector' ? <SelectorDetail addr={route.addr} navigate={navigate} />
          : route.kind === 'validator' ? <ValidatorDetail addr={route.addr} navigate={navigate} />
          : route.view === 'validators' ? <ValidatorsScreen navigate={navigate} />
          : route.view === 'selectors' ? <SelectorsScreen navigate={navigate} />
          : route.view === 'txs' ? <TxsScreen navigate={navigate} />
          : route.view === 'reports' ? <ReportsScreen navigate={navigate} />
          : route.view === 'bridge' ? <BridgeScreen navigate={navigate} />
          : route.view === 'disputes' ? <DisputesScreen navigate={navigate} />
          : <ReportersScreen navigate={navigate} />}
      </main>
      <footer className="foot muted small">
        <span className="foot-attrib">
          Part of
          <img src="/icons/nodeshub.png" alt="NodesHub" className="foot-logo" />
          <a href="https://nodeshub.online" target="_blank" rel="noopener" className="link"><b>NodesHub's</b></a> Public Goods Initiative
        </span>
      </footer>
      <ThemeToggle mode={mode} setMode={setMode} />
    </div>
  );
}

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