// app.jsx — main app

const { useState, useEffect, useMemo, useCallback } = React;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "density": "regular",
  "radius": "continuous",
  "accent": "#ff5b3b",
  "showSidebar": true,
  "iconSize": 116,
  "dark": false
} /*EDITMODE-END*/;

function parseHash() {
  const parts = window.location.hash.slice(1).split('/');
  return { page: parts[0] || 'discover', subId: parts[1] || null };
}

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [{ page, subId }, setRoute] = useState(parseHash);
  const [filters, setFilters] = useState({});
  const [openApp, setOpenApp] = useState(null);
  const [cmdK, setCmdK] = useState(false);
  const [visibleCount, setVisibleCount] = useState(36);

  const [apps, setApps] = useState(APPS);
  const [collections, setCollections] = useState(COLLECTIONS);
  const [user, setUser] = useState(null);
  const [showAuth, setShowAuth] = useState(false);
  const [favorites, setFavorites] = useState(new Set());

  // hash routing
  useEffect(() => {
    const onHash = () => { setRoute(parseHash()); window.scrollTo(0, 0); };
    window.addEventListener('hashchange', onHash);
    return () => window.removeEventListener('hashchange', onHash);
  }, []);

  // load data
  useEffect(() => {
    fetchApps().then(data => { if (data) setApps(data); });
    fetchCollections().then(data => { if (data) setCollections(data); });
  }, []);

  // auth
  useEffect(() => {
    supabase.auth.getSession().then(({ data: { session } }) => setUser(session?.user ?? null));
    const { data: { subscription } } = supabase.auth.onAuthStateChange((_e, session) => {
      setUser(session?.user ?? null);
      if (session?.user) setShowAuth(false);
    });
    return () => subscription.unsubscribe();
  }, []);

  useEffect(() => {
    if (user) fetchFavorites().then(ids => setFavorites(new Set(ids)));
    else setFavorites(new Set());
  }, [user]);

  const handleToggleFavorite = useCallback(async (appId) => {
    if (!user) { setShowAuth(true); return; }
    const isFav = favorites.has(appId);
    setFavorites(prev => { const n = new Set(prev); isFav ? n.delete(appId) : n.add(appId); return n; });
    const ok = await toggleFavorite(appId, isFav);
    if (!ok) setFavorites(prev => { const n = new Set(prev); isFav ? n.add(appId) : n.delete(appId); return n; });
  }, [user, favorites]);

  useEffect(() => {
    document.documentElement.dataset.theme = t.dark ? 'dark' : 'light';
    document.documentElement.style.setProperty('--accent', t.accent);
  }, [t.dark, t.accent]);

  useEffect(() => {
    const onKey = (e) => {
      if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'k') { e.preventDefault(); setCmdK(true); }
      else if (e.key === '/' && !e.metaKey && !e.ctrlKey && document.activeElement.tagName !== 'INPUT') { e.preventDefault(); setCmdK(true); }
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, []);

  const filtered = useMemo(() => {
    let r = apps.slice();
    if (filters.category?.length) r = r.filter(a => filters.category.includes(a.category));
    if (filters.color?.length) r = r.filter(a => a.colors?.some(c => filters.color.includes(c)));
    if (filters.style?.length) r = r.filter(a => a.styles?.some(s => filters.style.includes(s)));
    if (filters.pricing === 'free') r = r.filter(a => !a.paid);
    if (filters.pricing === 'paid') r = r.filter(a => a.paid);
    if (filters.year && filters.year !== 'all') r = r.filter(a => a.year === filters.year);
    if (filters.favorites) r = r.filter(a => favorites.has(a.id));
    if (filters.sort === 'rating') r.sort((a, b) => b.rating - a.rating);
    else if (filters.sort === 'recent') r.sort((a, b) => b.year - a.year || (b.id > a.id ? 1 : -1));
    else r.sort((a, b) => b.rating - a.rating);
    return r;
  }, [filters, apps, favorites]);

  const counts = useMemo(() => {
    const cat = {}, sty = {};
    apps.forEach(a => {
      cat[a.category] = (cat[a.category] || 0) + 1;
      a.styles?.forEach(s => sty[s] = (sty[s] || 0) + 1);
    });
    return { category: cat, style: sty };
  }, [apps]);

useEffect(() => {
    const onScroll = () => {
      if (window.innerHeight + window.scrollY >= document.body.offsetHeight - 600)
        setVisibleCount(c => Math.min(c + 12, filtered.length));
    };
    window.addEventListener('scroll', onScroll, { passive: true });
    return () => window.removeEventListener('scroll', onScroll);
  }, [filtered.length]);

  useEffect(() => { setVisibleCount(36); }, [filters]);

  const trending = useMemo(() => apps.slice().sort((a, b) => b.rating - a.rating).slice(0, 8), [apps]);

  const sharedProps = { apps, collections, favorites, onOpen: setOpenApp, onToggleFavorite: handleToggleFavorite, radius: t.radius };

  return (
    <div className="app">
      <TopBar onCmdK={() => setCmdK(true)} dark={t.dark} setDark={v => setTweak('dark', v)}
              user={user} onAuthClick={() => setShowAuth(true)} page={page} />

      <main className="main">
        {page === 'discover' && (
          <>
            <Hero onCmdK={() => setCmdK(true)} totalCount={apps.length} />
            <div className="container">
              <CollectionsRow collections={collections} onOpen={() => window.location.hash = 'collections'} />
              <TrendingRow apps={trending} onOpen={setOpenApp} />
            </div>
            <div className="container browse">
              <div className="browse-h">
                <div>
                  <h2 className="row-title">Browse all icons</h2>
                  <p className="row-sub">{filtered.length.toLocaleString()} icons · sorted by {filters.sort || 'popular'}</p>
                </div>
                <div className="active-chips">
                  {Object.entries(filters).flatMap(([k, v]) => {
                    if (!v || v === 'all' || v === false) return [];
                    if (k === 'favorites') return [{ k, v: 'Saved' }];
                    if (Array.isArray(v)) return v.map(x => ({ k, v: x }));
                    return [{ k, v }];
                  }).map(({ k, v }) =>
                    <button key={`${k}-${v}`} className="chip" onClick={() => {
                      const cur = filters[k];
                      if (Array.isArray(cur)) setFilters({ ...filters, [k]: cur.filter(x => x !== v) });
                      else { const f = { ...filters }; delete f[k]; setFilters(f); }
                    }}>{String(v)} <span>×</span></button>
                  )}
                </div>
              </div>
              <div className={`browse-grid ${t.showSidebar ? '' : 'no-side'}`}>
                {t.showSidebar &&
                  <FilterSidebar filters={filters} setFilters={setFilters} counts={counts}
                    user={user} favorites={favorites}
                    onFavoritesToggle={() => setFilters(f => ({ ...f, favorites: !f.favorites }))} />
                }
                <div className="grid-wrap">
                  {filtered.length === 0 ? (
                    <div className="empty-state">
                      <div className="empty-mark">○</div>
                      <h3>No icons match these filters</h3>
                      <p>Try removing a constraint or browsing a featured collection.</p>
                      <button className="ghost-btn" onClick={() => setFilters({})}>Reset filters</button>
                    </div>
                  ) : (
                    <div className="icon-grid" style={{ '--icon-size': `${t.iconSize}px` }}>
                      {filtered.slice(0, visibleCount).map(a =>
                        <IconCard key={a.id} app={a} size={t.iconSize} density={t.density} radius={t.radius}
                          onOpen={setOpenApp} isFavorited={favorites.has(a.id)} onToggleFavorite={handleToggleFavorite} />
                      )}
                    </div>
                  )}
                  {visibleCount < filtered.length && (
                    <div className="load-more">
                      <div className="skeleton-row">
                        {Array.from({ length: 6 }).map((_, i) =>
                          <div key={i} className="skel" style={{ width: t.iconSize, height: t.iconSize }} />
                        )}
                      </div>
                    </div>
                  )}
                </div>
              </div>
            </div>
          </>
        )}

        {page === 'collections' && (
          <CollectionsPage collections={collections} subId={subId} {...sharedProps} />
        )}

        {page === 'styles' && (
          <StylesPage apps={apps} onOpen={setOpenApp} radius={t.radius}
            onStyleClick={s => { window.location.hash = 'discover'; setFilters({ style: [s] }); }} />
        )}

        {page === 'submit' && (
          <SubmitPage user={user} onAuthClick={() => setShowAuth(true)} />
        )}

        <Footer />
      </main>

      <DetailPanel app={openApp} onClose={() => setOpenApp(null)} onOpen={setOpenApp}
        radius={t.radius} isFavorited={openApp && favorites.has(openApp.id)}
        onToggleFavorite={handleToggleFavorite} />
      <CmdK open={cmdK} onClose={() => setCmdK(false)} apps={apps} collections={collections} onOpenApp={setOpenApp} />
      {showAuth && <AuthModal onClose={() => setShowAuth(false)} />}

      <TweaksPanel>
        <TweakSection label="Density" />
        <TweakRadio label="Density" value={t.density} options={['compact', 'regular', 'comfy']}
          onChange={v => setTweak('density', v)} />
        <TweakSlider label="Icon size" value={t.iconSize} min={84} max={160} step={4} unit="px"
          onChange={v => setTweak('iconSize', v)} />
        <TweakToggle label="Filter sidebar" value={t.showSidebar} onChange={v => setTweak('showSidebar', v)} />
        <TweakSection label="Icon shape" />
        <TweakRadio label="Corner" value={t.radius} options={['continuous', 'circle', 'square']}
          onChange={v => setTweak('radius', v)} />
        <TweakSection label="Theme" />
        <TweakToggle label="Dark mode" value={t.dark} onChange={v => setTweak('dark', v)} />
        <TweakColor label="Accent" value={t.accent} options={['#ff5b3b', '#5b3df5', '#22b07a', '#0b0d12']}
          onChange={v => setTweak('accent', v)} />
      </TweaksPanel>
    </div>
  );
}

// ─── Auth Modal ───────────────────────────────────────────────────────────
function AuthModal({ onClose }) {
  const [email, setEmail] = useState('');
  const [sent, setSent] = useState(false);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState('');

  useEffect(() => {
    const onKey = e => e.key === 'Escape' && onClose();
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [onClose]);

  const submit = async e => {
    e.preventDefault(); setLoading(true); setError('');
    const { error } = await supabase.auth.signInWithOtp({ email, options: { emailRedirectTo: window.location.origin } });
    setLoading(false);
    if (error) setError(error.message); else setSent(true);
  };

  return (
    <div className="cmdk-overlay" onClick={onClose}>
      <div className="auth-modal" onClick={e => e.stopPropagation()}>
        <button className="detail-close" onClick={onClose} style={{ position: 'static', marginLeft: 'auto', display: 'flex' }}>
          <svg viewBox="0 0 24 24" width="14" height="14"><path d="M5 5L19 19M19 5L5 19" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" /></svg>
        </button>
        {sent ? (
          <div style={{ textAlign: 'center', padding: '8px 0 16px' }}>
            <div style={{ fontSize: 28, marginBottom: 12 }}>✉️</div>
            <h3 style={{ margin: '0 0 8px', fontSize: 18, fontWeight: 600 }}>Check your email</h3>
            <p style={{ color: 'var(--fg-mute)', margin: 0, fontSize: 14 }}>Magic link sent to <strong>{email}</strong></p>
          </div>
        ) : (
          <>
            <h3 style={{ margin: '0 0 6px', fontSize: 18, fontWeight: 600 }}>Save your favorites</h3>
            <p style={{ margin: '0 0 20px', color: 'var(--fg-mute)', fontSize: 14 }}>Enter your email — no password needed.</p>
            <form onSubmit={submit} style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
              <input type="email" required placeholder="you@example.com" value={email}
                onChange={e => setEmail(e.target.value)} autoFocus
                style={{ border: '1px solid var(--line)', borderRadius: 9, padding: '10px 14px', fontSize: 14,
                         background: 'var(--bg-soft)', color: 'var(--fg)', fontFamily: 'inherit', outline: 'none' }} />
              {error && <p style={{ color: 'var(--accent)', fontSize: 13, margin: 0 }}>{error}</p>}
              <button type="submit" className="primary-btn block" disabled={loading}>
                {loading ? 'Sending…' : 'Send magic link'}
              </button>
            </form>
          </>
        )}
      </div>
    </div>
  );
}

function Footer() {
  return (
    <footer className="foot">
      <div className="container foot-inner">
        <div className="foot-l">
          <div className="brand"><span className="brand-name">App<span className="brand-light">Store</span>Icons</span></div>
          <p className="foot-pitch">A reference for iOS icon design. Curated weekly.</p>
        </div>
        <div className="foot-cols">
          <div>
            <div className="foot-h">Browse</div>
            <a href="#discover">Discover</a><a href="#collections">Collections</a><a href="#styles">Styles</a>
          </div>
          <div>
            <div className="foot-h">Resources</div>
            <a href="#submit">Submit an icon</a><a href="#">Changelog</a>
          </div>
          <div>
            <div className="foot-h">Company</div>
            <a href="#">About</a><a href="#">Twitter</a><a href="#">Contact</a>
          </div>
        </div>
      </div>
      <div className="foot-bottom">
        <span>© 2026 AppStoreIcons. Independent. Original work only.</span>
        <span>v 1.0 · Made for iOS designers</span>
      </div>
    </footer>
  );
}

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