/* the turn - redesign app shell. Four tabs (Today / Explore / Log / Field
   Guide), a drill-down stack (species / area / catch), the log-form overlay,
   theme, toasts, and the Tweaks panel (Today-card layout variants live here). */

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "todayLayout": "band",
  "theme": "light",
  "aheadOpen": false
}/*EDITMODE-END*/;

/* Honest data-state banner. Reads the flags main.tsx sets on every build:
   - not real (demo bootstrap still showing)  -> "sample data, not live"
   - real but last refresh errored (offline)  -> "couldn't refresh, X old"
   Silent when data is real and fresh. Re-renders on turn:dataReady. */
function DataHonestyBanner() {
  const { useState, useEffect } = React;
  const [, bump] = useState(0);
  useEffect(() => {
    const onReady = () => bump((v) => v + 1);
    window.addEventListener('turn:dataReady', onReady);
    const id = setInterval(onReady, 60000); // refresh the "X ago" text
    return () => { window.removeEventListener('turn:dataReady', onReady); clearInterval(id); };
  }, []);

  const isReal = window.__turnDataIsReal === true;
  const err = window.__turnDataError;
  const at = window.__turnDataAt;
  if (isReal && !err) return null; // all good, no banner

  const ageMin = at ? Math.round((Date.now() - at) / 60000) : null;
  const ageStr = ageMin == null ? null : ageMin < 1 ? 'moments ago' : ageMin < 60 ? `${ageMin} min ago` : `${Math.round(ageMin / 60)}h ago`;

  let msg, tone;
  if (!isReal) {
    msg = 'Sample data — not your live conditions. Connect to refresh.';
    tone = 'var(--verdict-caution)';
  } else {
    msg = `Couldn't refresh — showing last live read${ageStr ? ` from ${ageStr}` : ''}. Conditions may have changed.`;
    tone = 'var(--verdict-caution)';
  }
  return (
    <div role="status" style={{
      display: 'flex', alignItems: 'center', gap: 8,
      padding: '8px var(--gutter)', flex: '0 0 auto',
      background: 'color-mix(in srgb, var(--verdict-caution) 14%, var(--bg))',
      borderBottom: '1px solid color-mix(in srgb, var(--verdict-caution) 40%, transparent)',
      fontFamily: 'var(--font-mono)', fontSize: 11.5, color: tone, lineHeight: 1.3,
    }}>
      <span style={{ flex: '0 0 auto', width: 7, height: 7, borderRadius: '50%', background: tone }} />
      <span style={{ minWidth: 0 }}>{msg}</span>
    </div>
  );
}

function TurnApp() {
  const { useState, useEffect } = React;
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);

  const [tab, setTab] = useState('today');
  const [stack, setStack] = useState([]);          // drill-down stack
  const [logForm, setLogForm] = useState(undefined); // undefined=closed, else areaId|null
  const [toast, setToast] = useState(null);
  const [aheadOpen, setAheadOpen] = useState(t.aheadOpen);
  const [aheadActive, setAheadActive] = useState(0);

  // Force re-render when the Vite-driven engine upgrades window.TURN from
  // demo data to real engine data. main.tsx fires 'turn:dataReady' once it's done.
  const [, setDataVersion] = useState(0);
  useEffect(() => {
    const onReady = () => setDataVersion((v) => v + 1);
    window.addEventListener('turn:dataReady', onReady);
    return () => window.removeEventListener('turn:dataReady', onReady);
  }, []);

  useEffect(() => { document.documentElement.dataset.theme = t.theme; }, [t.theme]);
  useEffect(() => { setAheadOpen(t.aheadOpen); }, [t.aheadOpen]);

  const top = stack[stack.length - 1];
  const push = (entry) => setStack(s => [...s, entry]);
  const back = () => setStack(s => s.slice(0, -1));

  const onSpecies = (id) => push({ type: 'species', id });
  const onArea = (id) => push({ type: 'area', id });
  const onCatch = (id) => push({ type: 'catch', id });
  const onNewLog = (areaId) => setLogForm(areaId ?? null);
  const goExplore = () => { setStack([]); setTab('explore'); };

  const fireToast = (msg) => { setToast(msg); clearTimeout(window.__tt); window.__tt = setTimeout(() => setToast(null), 2800); };
  const onSavedLog = (name, outcome) => {
    setLogForm(undefined);
    fireToast(outcome === 'went'
      ? { k: 'catch', title: `Banked · ${name}`, sub: 'good oil - that sharpens the next call' }
      : { k: 'blank', title: `${outcome === 'skipped' ? 'Skip' : 'Abort'} logged · ${name}`, sub: 'a donut, but it all counts' });
  };

  return (
    <PhoneFrame>
      <div style={{ position: 'absolute', inset: 0, display: 'flex', flexDirection: 'column' }}>
        {/* header */}
        <header style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '4px var(--gutter) 12px', borderBottom: '1px solid var(--hairline)', flex: '0 0 auto' }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
            <Mark size={30} />
            <span style={{ fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 19, color: 'var(--text)', letterSpacing: '-0.02em', whiteSpace: 'nowrap' }}>the <span style={{ color: 'var(--verdict-go)' }}>turn</span></span>
          </div>
          <button onClick={() => setTweak('theme', t.theme === 'dark' ? 'light' : 'dark')} aria-label="toggle theme" style={{ width: 34, height: 34, borderRadius: '50%', display: 'grid', placeItems: 'center', background: 'var(--surface)', border: '1px solid var(--border)', color: 'var(--text-dim)', cursor: 'pointer' }}>
            <Icon name={t.theme === 'dark' ? 'sun' : 'moon'} size={17} />
          </button>
        </header>

        {/* honesty banner — never let demo/stale data pose as a live call */}
        <DataHonestyBanner />

        {/* main */}
        <main style={{ flex: 1, minHeight: 0, position: 'relative', overflowY: 'auto', overflowX: 'hidden' }}>
          <div style={{ padding: '12px 0' }}>
            {tab === 'today' && <Today layout={t.todayLayout} onSpecies={onSpecies} onArea={onArea} onLog={onNewLog} onExplore={goExplore} onConditions={() => setTab('conditions')} aheadOpen={aheadOpen} setAheadOpen={setAheadOpen} aheadActive={aheadActive} setAheadActive={setAheadActive} />}
            {tab === 'explore' && <Explore onArea={onArea} onSpecies={onSpecies} onConditions={() => setTab('conditions')} />}
            {tab === 'conditions' && React.createElement(window.Conditions)}
            {tab === 'guide' && <FieldGuide onSpecies={onSpecies} />}
          </div>
        </main>

        <BottomNav tab={tab} onTab={(id) => { setStack([]); setTab(id); }} style={{ flex: '0 0 auto' }} />
      </div>

      {/* drill-down stack overlay */}
      {top && (
        <div style={{ position: 'absolute', inset: '50px 0 0', zIndex: 40, background: 'var(--bg)' }}>
          {top.type === 'species' && <SpeciesPage id={top.id} onBack={back} onArea={onArea} />}
          {top.type === 'area' && <AreaDetail id={top.id} onBack={back} onSpecies={onSpecies} onArea={onArea} onLog={onCatch} onNewLog={onNewLog} />}
          {top.type === 'catch' && <CatchDetail id={top.id} onBack={back} onArea={onArea} onSpecies={onSpecies} />}
        </div>
      )}

      {/* floating Log button — always reachable, on every tab + drill-down.
          Pre-fills the area you're looking at (or today's best play). Hidden
          only while the log form itself is open. */}
      {logForm === undefined && (
        <button
          onClick={() => onNewLog(top && top.type === 'area' ? top.id : undefined)}
          aria-label="log a catch"
          style={{
            position: 'absolute', zIndex: 45,
            right: 18, bottom: 'calc(80px + var(--safe-bottom, 0px))',
            width: 58, height: 58, borderRadius: '50%',
            display: 'grid', placeItems: 'center',
            background: 'var(--verdict-go)', color: 'var(--text-on-go)',
            border: 'none', cursor: 'pointer',
            boxShadow: '0 6px 20px rgba(12,59,38,0.30), 0 0 0 1px color-mix(in srgb, var(--verdict-go) 50%, transparent)',
          }}
        >
          <span style={{ display: 'grid', transform: 'scaleX(-1)' }}>
            <FishIcon species="grunter" size={32} color="var(--text-on-go)" strokeWidth={2} />
          </span>
        </button>
      )}

      {/* log form overlay */}
      {logForm !== undefined && <LogForm areaId={logForm} onClose={() => setLogForm(undefined)} onSaved={onSavedLog} />}

      {/* toast */}
      {toast && (
        <div style={{ position: 'absolute', left: 16, right: 16, bottom: 96, zIndex: 60, display: 'flex', alignItems: 'center', gap: 12, padding: '14px 16px', background: 'var(--surface-raised)', border: '1px solid var(--border-strong)', borderRadius: 'var(--r-md)', boxShadow: 'var(--shadow-pop)' }}>
          <span style={{ width: 36, height: 36, borderRadius: '50%', display: 'grid', placeItems: 'center', background: toast.k === 'catch' ? 'color-mix(in srgb, var(--verdict-go) 22%, var(--bg))' : 'var(--surface)', border: `1.5px solid ${toast.k === 'catch' ? 'var(--verdict-go)' : 'var(--border-strong)'}`, color: toast.k === 'catch' ? 'var(--verdict-go)' : 'var(--text-dim)', flex: '0 0 auto' }}>
            <Icon name={toast.k === 'catch' ? 'plus' : 'blank'} size={18} />
          </span>
          <div>
            <div style={{ fontWeight: 700, fontSize: 15, color: 'var(--text)' }}>{toast.title}</div>
            <div style={{ fontSize: 12, color: 'var(--text-dim)' }}>{toast.sub}</div>
          </div>
        </div>
      )}

      {/* Tweaks */}
      <TweaksPanel>
        <TweakSection label="Today card" />
        <TweakRadio label="Layout" value={t.todayLayout} options={['band', 'instrument', 'split']} onChange={(v) => setTweak('todayLayout', v)} />
        <TweakSection label="Look-ahead" />
        <TweakToggle label="Expand Ahead strip" value={t.aheadOpen} onChange={(v) => setTweak('aheadOpen', v)} />
        <TweakSection label="Theme" />
        <TweakRadio label="Mode" value={t.theme} options={['dark', 'light']} onChange={(v) => setTweak('theme', v)} />
      </TweaksPanel>
    </PhoneFrame>
  );
}

window.TurnApp = TurnApp;

/* Root - one app, two shells. Wide screens get the desktop dashboard
   (DesktopShell); phones/tablets keep the PhoneFrame stack. Switches live on
   resize so a window drag flips between them. The ≥1024px break is below most
   laptops but above tablets in portrait. */
function Root() {
  const { useState, useEffect } = React;
  const MQ = '(min-width: 1024px)';
  const [desktop, setDesktop] = useState(() => typeof window.matchMedia === 'function' && window.matchMedia(MQ).matches);
  useEffect(() => {
    if (typeof window.matchMedia !== 'function') return;
    const m = window.matchMedia(MQ);
    const on = () => setDesktop(m.matches);
    m.addEventListener('change', on);
    return () => m.removeEventListener('change', on);
  }, []);
  return desktop && window.DesktopShell ? <DesktopShell /> : <TurnApp />;
}
window.Root = Root;
