// app.jsx — PsyFit shell: nav, state, sheets, tweaks, scaling

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accent": "#C8FF2E",
  "imagery": true,
  "font": "Anton",
  "dark": true,
  "radius": 18,
  "homeLayout": "Hero"
}/*EDITMODE-END*/;

const clone = (o) => JSON.parse(JSON.stringify(o));

const SETTINGS_DEFAULTS = {
  unit: 'lb',
  reminderOn: true,
  reminderTime: '18:00',
  weeklyGoal: 5,
};

// Running as an installed app (added to home screen)?
const STANDALONE = (typeof window !== 'undefined') &&
  (window.matchMedia('(display-mode: standalone)').matches || window.navigator.standalone === true);

// ── Local persistence ────────────────────────────────────────
function loadLS(key, fallback) {
  try { const v = localStorage.getItem('psyfit:' + key); return v ? JSON.parse(v) : fallback; }
  catch (e) { return fallback; }
}
function saveLS(key, val) {
  try { localStorage.setItem('psyfit:' + key, JSON.stringify(val)); } catch (e) {}
}

// ── Bottom navigation ────────────────────────────────────────
function BottomNav({ screen, go, standalone }) {
  const c = useTheme();
  const items = [
    { id: 'home', icon: 'home', label: 'Home' },
    { id: 'plan', icon: 'plan', label: 'Plan' },
    { id: 'log', icon: 'bolt', label: 'Log', center: true },
    { id: 'progress', icon: 'progress', label: 'Stats' },
    { id: 'calendar', icon: 'calendar', label: 'Calendar' },
  ];
  return (
    <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-around',
      padding: standalone ? '10px 12px calc(env(safe-area-inset-bottom) + 14px)' : '10px 12px 26px',
      background: c.dark ? 'rgba(10,11,13,0.86)' : 'rgba(243,244,241,0.9)',
      backdropFilter: 'blur(18px) saturate(160%)', WebkitBackdropFilter: 'blur(18px) saturate(160%)',
      borderTop: '1px solid var(--border)', flexShrink: 0 }}>
      {items.map(it => {
        const active = screen === it.id;
        if (it.center) {
          return (
            <button key={it.id} onClick={() => go(it.id)} style={{ width: 56, height: 56, marginTop: -6, borderRadius: 999,
              background: c.accent, color: c.accentInk, border: 'none', cursor: 'pointer',
              display: 'flex', alignItems: 'center', justifyContent: 'center',
              boxShadow: `0 8px 24px -6px ${c.accent}` }}>
              <Icon name={it.icon} size={26} />
            </button>
          );
        }
        return (
          <button key={it.id} onClick={() => go(it.id)} style={{ background: 'none', border: 'none', cursor: 'pointer',
            display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 4, width: 58, padding: '4px 0',
            color: active ? c.accent : 'var(--dim)' }}>
            <Icon name={it.icon} size={23} stroke={active ? 2.4 : 2} />
            <span style={{ fontFamily: 'var(--font-body)', fontSize: 10, fontWeight: 700, letterSpacing: 0.3 }}>{it.label}</span>
          </button>
        );
      })}
    </div>
  );
}

// ── Top bar ──────────────────────────────────────────────────
function TopBar({ screen, go, back, standalone }) {
  const c = useTheme();
  const pushed = screen === 'library' || screen === 'profile';
  return (
    <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between',
      padding: standalone ? 'calc(env(safe-area-inset-top) + 14px) 20px 12px' : '52px 20px 12px', flexShrink: 0 }}>
      {pushed ? (
        <button onClick={back} style={{ display: 'flex', alignItems: 'center', gap: 6, background: 'none', border: 'none', cursor: 'pointer', color: 'var(--text)', fontFamily: 'var(--font-body)', fontWeight: 700, fontSize: 14 }}>
          <Icon name="chevL" size={20} /> Back
        </button>
      ) : (
        <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
          <div style={{ width: 24, height: 24, borderRadius: 7, background: c.accent, color: c.accentInk, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
            <Icon name="bolt" size={15} />
          </div>
          <span style={{ fontFamily: 'var(--font-display)', fontSize: 22, letterSpacing: 1, color: 'var(--text)' }}>PSY<span style={{ color: c.accent }}>FIT</span></span>
        </div>
      )}
      {screen !== 'profile' && (
        <AppPhoto id="avatar" shape="circle" interactive={false} onClick={() => go('profile')}
          placeholderIcon="profile" placeholder=""
          style={{ width: 36, height: 36, border: '1.5px solid var(--border)' }} />
      )}
    </div>
  );
}

// ── Bottom sheet ─────────────────────────────────────────────
function Sheet({ kind, onClose, addExercise, profile, setProfile }) {
  const c = useTheme();
  const [name, setName] = React.useState(kind === 'edit-profile' ? profile.name : '');
  const [muscle, setMuscle] = React.useState('Chest');
  const [gear, setGear] = React.useState('Barbell');

  const title = kind === 'add-exercise' ? 'New Exercise' : 'Edit Profile';
  const canSave = kind === 'add-exercise' ? name.trim().length > 0 : name.trim().length > 0;

  const save = () => {
    if (kind === 'add-exercise') {
      addExercise({ id: 'c' + Date.now(), name: name.trim(), muscle, gear, custom: true });
    } else {
      setProfile(p => ({ ...p, name: name.trim() }));
    }
    onClose();
  };

  return (
    <div style={{ position: 'absolute', inset: 0, zIndex: 45, display: 'flex', flexDirection: 'column', justifyContent: 'flex-end' }}>
      <div onClick={onClose} style={{ position: 'absolute', inset: 0, background: 'rgba(0,0,0,0.55)', animation: 'psyfade .2s ease' }} />
      <div style={{ position: 'relative', background: 'var(--surface)', borderTopLeftRadius: 28, borderTopRightRadius: 28,
        borderTop: '1px solid var(--border)', padding: '14px 20px 34px', animation: 'psyslide .28s cubic-bezier(.2,.8,.2,1)' }}>
        <div style={{ width: 40, height: 5, borderRadius: 999, background: 'var(--surface-3)', margin: '0 auto 16px' }} />
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 18 }}>
          <Display size={26}>{title}</Display>
          <button onClick={onClose} style={{ background: 'var(--surface-2)', border: 'none', borderRadius: 999, width: 34, height: 34, color: 'var(--text)', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center' }}><Icon name="close" size={18} /></button>
        </div>

        <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
          <div>
            <Eyebrow style={{ marginBottom: 8 }}>{kind === 'add-exercise' ? 'Exercise name' : 'Display name'}</Eyebrow>
            <input autoFocus value={name} onChange={e => setName(e.target.value)} placeholder={kind === 'add-exercise' ? 'e.g. Landmine Press' : 'Your name'}
              style={{ width: '100%', boxSizing: 'border-box', height: 48, padding: '0 16px', borderRadius: 'var(--radius-sm)',
                background: 'var(--surface-2)', border: '1px solid var(--border)', color: 'var(--text)', fontFamily: 'var(--font-body)', fontSize: 16, outline: 'none' }} />
          </div>

          {kind === 'add-exercise' ? (
            <>
              <div>
                <Eyebrow style={{ marginBottom: 8 }}>Muscle group</Eyebrow>
                <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8 }}>
                  {MUSCLES.map(m => <Chip key={m} active={muscle === m} onClick={() => setMuscle(m)}>{m}</Chip>)}
                </div>
              </div>
              <div>
                <Eyebrow style={{ marginBottom: 8 }}>Equipment</Eyebrow>
                <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8 }}>
                  {['Barbell', 'Dumbbell', 'Machine', 'Cable', 'Bodyweight'].map(g => <Chip key={g} active={gear === g} onClick={() => setGear(g)}>{g}</Chip>)}
                </div>
              </div>
            </>
          ) : null}

          <AccentButton onClick={save} style={{ opacity: canSave ? 1 : 0.4, pointerEvents: canSave ? 'auto' : 'none' }} icon={<Icon name="check" size={18} />}>Save</AccentButton>
        </div>
      </div>
    </div>
  );
}

// ── App ──────────────────────────────────────────────────────
function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  // Theme is localStorage-backed so it survives on the deployed PWA, where the
  // Tweaks host (which normally persists changes to disk) isn't present.
  const [theme, setThemeState] = React.useState(() => loadLS('theme', { ...TWEAK_DEFAULTS }));
  const setPref = React.useCallback((key, val) => {
    setThemeState(prev => { const n = { ...prev, [key]: val }; saveLS('theme', n); return n; });
    try { setTweak(key, val); } catch (e) {}
  }, [setTweak]);

  const [settings, setSettingsState] = React.useState(() => loadLS('settings', { ...SETTINGS_DEFAULTS }));
  const setSettings = React.useCallback((edits) => {
    setSettingsState(prev => { const n = { ...prev, ...edits }; saveLS('settings', n); return n; });
  }, []);

  const [cleared, setClearedState] = React.useState(() => loadLS('cleared', false));
  const setCleared = React.useCallback((v) => { setClearedState(v); saveLS('cleared', v); }, []);

  const colors = makeColors(theme);
  const ctxColors = { ...colors, ...makeUnit(settings.unit), cleared };

  const [screen, setScreen] = React.useState('home');
  const prev = React.useRef('home');
  const [plan, setPlan] = React.useState(() => loadLS('plan', clone(TODAY_PLAN)));
  const [library, setLibrary] = React.useState(() => loadLS('library', clone(LIBRARY)));
  const [profile, setProfile] = React.useState(() => loadLS('profile', clone(PROFILE)));
  const [sheet, setSheet] = React.useState(null);
  const [anim, setAnim] = React.useState(0);
  const bodyRef = React.useRef(null);
  const scalerRef = React.useRef(null);

  const screenRef = React.useRef('home');
  screenRef.current = screen;

  const go = (s) => {
    if (s === screen && !sheet) return;
    prev.current = screen;
    if (sheet) setSheet(null);
    setScreen(s);
    setAnim(a => a + 1);
    if (bodyRef.current) bodyRef.current.scrollTop = 0;
    try { window.history.pushState({ screen: s, sheet: null }, ''); } catch (e) {}
  };
  const openSheet = (k) => {
    setSheet(k);
    try { window.history.pushState({ screen: screenRef.current, sheet: k }, ''); } catch (e) {}
  };
  const closeSheet = () => { try { window.history.back(); } catch (e) { setSheet(null); } };
  const back = () => { try { window.history.back(); } catch (e) { go('home'); } };

  // workout state ops
  const toggleSet = (ei, si) => setPlan(p => { const n = clone(p); n.exercises[ei].sets[si].done = !n.exercises[ei].sets[si].done; return n; });
  const addSet = (ei, set) => setPlan(p => { const n = clone(p); n.exercises[ei].sets.push(set); return n; });
  const removeSet = (ei, si) => setPlan(p => { const n = clone(p); n.exercises[ei].sets.splice(si, 1); return n; });
  const addToPlan = (exId) => { setPlan(p => { const n = clone(p); if (!n.exercises.find(e => e.id === exId)) n.exercises.push({ id: exId, sets: [{ reps: 10, weight: 45, done: false }] }); return n; }); go('plan'); };
  const addExercise = (ex) => setLibrary(l => [{ ...ex }, ...l]);

  const total = plan.exercises.reduce((s, e) => s + e.sets.length, 0);
  const done = plan.exercises.reduce((s, e) => s + e.sets.filter(x => x.done).length, 0);
  const pct = total ? Math.round((done / total) * 100) : 0;

  // persist workout data locally so nothing resets on reload / reopen
  React.useEffect(() => { saveLS('plan', plan); }, [plan]);
  React.useEffect(() => { saveLS('library', library); }, [library]);
  React.useEffect(() => { saveLS('profile', profile); }, [profile]);

  // Android/browser back button drives in-app navigation via the History API.
  React.useEffect(() => {
    try { window.history.replaceState({ screen: 'home', sheet: null }, ''); } catch (e) {}
    const onPop = (e) => {
      const stt = (e && e.state) || { screen: 'home', sheet: null };
      setSheet(stt.sheet || null);
      const ns = stt.screen || 'home';
      if (ns !== screenRef.current) {
        setScreen(ns);
        setAnim(a => a + 1);
        if (bodyRef.current) bodyRef.current.scrollTop = 0;
      }
    };
    window.addEventListener('popstate', onPop);
    return () => window.removeEventListener('popstate', onPop);
  }, []);

  // scaling (framed preview only)
  React.useEffect(() => {
    if (STANDALONE) return;
    const fit = () => {
      if (!scalerRef.current) return;
      const s = Math.min(window.innerWidth / 402, window.innerHeight / 874, 1.1);
      scalerRef.current.style.transform = `scale(${s})`;
    };
    fit();
    window.addEventListener('resize', fit);
    return () => window.removeEventListener('resize', fit);
  }, []);

  // expose live exercise lookup using current library
  React.useEffect(() => { window.exById = (id) => library.find(e => e.id === id) || LIBRARY.find(e => e.id === id) || { name: id, muscle: '', gear: '' }; }, [library]);

  // daily reminder (fires while the app is open / backgrounded)
  React.useEffect(() => {
    if (!settings.reminderOn) return;
    if (!('Notification' in window) || Notification.permission !== 'granted') return;
    let timer;
    const schedule = () => {
      const [h, m] = String(settings.reminderTime).split(':').map(Number);
      const now = new Date();
      const next = new Date();
      next.setHours(h, m, 0, 0);
      if (next <= now) next.setDate(next.getDate() + 1);
      timer = setTimeout(() => {
        try { new Notification('PsyFit', { body: "Time to train. Don't break the streak \uD83D\uDD25", icon: 'icons/icon-192.png' }); } catch (e) {}
        schedule();
      }, next - now);
    };
    schedule();
    return () => clearTimeout(timer);
  }, [settings.reminderOn, settings.reminderTime]);

  // backup payload + restore
  const getExport = () => ({ plan, library, profile, settings, theme, cleared, photos: allPhotos() });
  const onImport = (data) => {
    if (data.plan) setPlan(data.plan);
    if (data.library) setLibrary(data.library);
    if (data.profile) setProfile(data.profile);
    if (data.settings) setSettingsState(s => { const n = { ...s, ...data.settings }; saveLS('settings', n); return n; });
    if (data.theme) setThemeState(th => { const n = { ...th, ...data.theme }; saveLS('theme', n); return n; });
    setCleared(!!data.cleared);
    if (data.photos) { try { Object.entries(data.photos).forEach(([id, url]) => savePhoto(id, url)); } catch (e) {} }
  };

  // wipe logged history — unticks every set and flags history as cleared so
  // streaks, charts, calendar and PRs read empty.
  const clearHistory = () => {
    setCleared(true);
    setPlan(p => { const n = clone(p); n.exercises.forEach(e => e.sets.forEach(s => { s.done = false; })); return n; });
  };

  const SETTINGS_KINDS = ['units', 'reminders', 'goal', 'preferences', 'data'];

  const screenEl = (() => {
    switch (screen) {
      case 'home': return <HomeScreen layout={theme.homeLayout} plan={plan} pct={pct} go={go} streak={cleared ? 0 : profile.stats.streak} />;
      case 'plan': return <PlanScreen plan={plan} pct={pct} toggleSet={toggleSet} go={go} />;
      case 'log': return <LogScreen plan={plan} addSet={addSet} toggleSet={toggleSet} removeSet={removeSet} go={go} />;
      case 'progress': return <ProgressScreen />;
      case 'calendar': return <CalendarScreen />;
      case 'library': return <LibraryScreen library={library} openSheet={openSheet} addToPlan={addToPlan} />;
      case 'profile': return <ProfileScreen openSheet={openSheet} profile={profile} settings={settings} />;
      default: return null;
    }
  })();

  const shell = (
    <div style={{ height: '100%', display: 'flex', flexDirection: 'column', background: 'var(--bg)', position: 'relative', overflow: 'hidden' }}>
      <TopBar screen={screen} go={go} back={back} standalone={STANDALONE} />
      <div ref={bodyRef} style={{ flex: 1, overflowY: 'auto', overflowX: 'hidden', padding: '4px 20px 24px' }}>
        <div key={anim} style={{ animation: 'psyenter .32s cubic-bezier(.2,.8,.2,1)' }}>
          {screenEl}
        </div>
      </div>
      <BottomNav screen={screen} go={go} standalone={STANDALONE} />
      {sheet && (SETTINGS_KINDS.includes(sheet)
        ? <SettingsSheet kind={sheet} onClose={closeSheet} ctx={{ settings, setSettings, theme, setPref, getExport, onImport, clearHistory }} />
        : <Sheet kind={sheet} onClose={closeSheet} addExercise={addExercise} profile={profile} setProfile={setProfile} />)}
    </div>
  );

  return (
    <ThemeContext.Provider value={ctxColors}>
      {STANDALONE ? (
        // Installed app: fill the real device, no bezel.
        <div style={{ ...cssVars(colors), position: 'fixed', inset: 0, background: 'var(--bg)' }}>
          {shell}
        </div>
      ) : (
        // Browser preview: framed phone, scaled to fit.
        <div className="psyfit-stage">
          <div className="psyfit-scaler" ref={scalerRef}>
            <div style={cssVars(colors)}>
              <IOSDevice dark={colors.dark} width={402} height={874}>
                {shell}
              </IOSDevice>
            </div>
          </div>
        </div>
      )}

      <TweaksPanel>
        <TweakSection label="Home" />
        <TweakRadio label="Home layout" value={theme.homeLayout} options={['Hero', 'Stats', 'Editorial']} onChange={v => { setPref('homeLayout', v); go('home'); }} />
        <TweakSection label="Brand" />
        <TweakColor label="Accent" value={theme.accent} options={ACCENTS.map(a => a.c)} onChange={v => setPref('accent', v)} />
        <TweakRadio label="Font" value={theme.font} options={['Anton', 'Bebas', 'Oswald']} onChange={v => setPref('font', v)} />
        <TweakSection label="Appearance" />
        <TweakToggle label="Dark mode" value={theme.dark} onChange={v => setPref('dark', v)} />
        <TweakToggle label="Imagery" value={theme.imagery} onChange={v => setPref('imagery', v)} />
        <TweakSlider label="Corner radius" value={theme.radius} min={4} max={28} step={1} unit="px" onChange={v => setPref('radius', v)} />
      </TweaksPanel>
    </ThemeContext.Provider>
  );
}

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