/* ===== Main app: shell, routing, state, tweaks ===== */

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accent": "#6243EB",
  "theme": "light",
  "density": "regular",
  "fontPair": "modern",
  "rail": false
}/*EDITMODE-END*/;

const FONT_PAIRS = {
  modern:    { display: "'Inter'", ui: "'Inter'" },
  geometric: { display: "'Inter'", ui: "'Inter'" },
  playful:   { display: "'Inter'", ui: "'Inter'" }
};

const NAV_MAIN = [
  { id: 'dashboard', label: 'Dashboard', icon: 'dashboard' },
  { id: 'browse', label: 'Library', icon: 'library' },
  { id: 'collections', label: 'Collections', icon: 'collections' },
  { id: 'favorites', label: 'Favorites', icon: 'heart' },
  { id: 'manage', label: 'My Sections', icon: 'folder' }
];

function App({ user, onSignOut }) {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [route, setRoute] = useState({ view: 'dashboard' });
  const [search, setSearch] = useState('');
  const [favs, setFavs] = useState(() => {
    var v = window.Store.get('favs'); return Array.isArray(v) ? v : [];
  });
  const [catsOpen, setCatsOpen] = useState(() => {
    var v = window.Store.get('catsOpen'); return v === undefined ? true : !!v;
  });
  useEffect(() => { window.Store.set('catsOpen', catsOpen); }, [catsOpen]);

  const [profile, setProfileState] = useState(() => {
    var def = { role: 'Frontend Developer', company: 'Sectionly', bio: 'Building beautiful frontends, one section at a time.',
      notif: { product: true, weekly: true, mentions: true, marketing: false }, twoFactor: false };
    var saved = window.Store.get('profile');
    var base = Object.assign(def, saved && typeof saved === 'object' ? saved : {});
    // Identity (name/email/avatar) is owned by the signed-in account.
    return Object.assign(base, {
      name: user.name, email: user.email,
      avatar: user.avatar || base.avatar || '',
      provider: user.provider, verified: user.verified
    });
  });
  const setProfile = useCallback((patch) => {
    setProfileState(prev => {
      var next = typeof patch === 'function' ? patch(prev) : Object.assign({}, prev, patch);
      window.Store.set('profile', next);
      // keep the account record (and other devices) in sync with identity edits
      if (patch && typeof patch === 'object' && (patch.name != null || patch.email != null || patch.avatar != null)) {
        window.Auth.updateAccount({ name: next.name, email: next.email, avatar: next.avatar });
      }
      return next;
    });
  }, []);
  // reflect external account changes (e.g. another device) into the sidebar
  useEffect(() => {
    setProfileState(prev => Object.assign({}, prev, {
      name: user.name, email: user.email,
      avatar: user.avatar || prev.avatar || '',
      provider: user.provider, verified: user.verified
    }));
  }, [user.name, user.email, user.avatar, user.verified]);
  const searchRef = useRef(null);
  const [notifOpen, setNotifOpen] = useState(false);
  const notifRef = useRef(null);
  const [userMenuOpen, setUserMenuOpen] = useState(false);
  const userMenuRef = useRef(null);
  useEffect(() => {
    if (!userMenuOpen) return;
    const onDoc = (e) => { if (userMenuRef.current && !userMenuRef.current.contains(e.target)) setUserMenuOpen(false); };
    const onKey = (e) => { if (e.key === 'Escape') setUserMenuOpen(false); };
    document.addEventListener('mousedown', onDoc);
    document.addEventListener('keydown', onKey);
    return () => { document.removeEventListener('mousedown', onDoc); document.removeEventListener('keydown', onKey); };
  }, [userMenuOpen]);
  useEffect(() => {
    if (!notifOpen) return;
    const onDoc = (e) => { if (notifRef.current && !notifRef.current.contains(e.target)) setNotifOpen(false); };
    const onKey = (e) => { if (e.key === 'Escape') setNotifOpen(false); };
    document.addEventListener('mousedown', onDoc);
    document.addEventListener('keydown', onKey);
    return () => { document.removeEventListener('mousedown', onDoc); document.removeEventListener('keydown', onKey); };
  }, [notifOpen]);
  const [version, setVersion] = useState(0);
  const refresh = useCallback(() => setVersion(v => v + 1), []);
  const [toast, setToast] = useState(null);
  const toastT = useRef(null);
  const notify = useCallback((msg, error) => {
    setToast({ msg: msg, error: !!error });
    if (toastT.current) clearTimeout(toastT.current);
    toastT.current = setTimeout(() => setToast(null), 2400);
  }, []);

  useEffect(() => { window.Store.set('favs', favs); }, [favs]);

  const toggleFav = useCallback((id) => {
    setFavs(prev => prev.includes(id) ? prev.filter(x => x !== id) : [...prev, id]);
  }, []);

  const nav = useCallback((r) => {
    if (r.view !== 'browse') setSearch('');
    setRoute(r);
    const el = document.querySelector('.content'); if (el) el.scrollTop = 0;
  }, []);

  /* cmd+k focuses search */
  useEffect(() => {
    const onKey = (e) => {
      if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'k') {
        e.preventDefault(); searchRef.current && searchRef.current.focus();
      }
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, []);

  const onSearch = (v) => {
    setSearch(v);
    if (v && route.view !== 'browse') setRoute({ view: 'browse' });
  };

  const fp = FONT_PAIRS[t.fontPair] || FONT_PAIRS.modern;
  const rootStyle = {
    '--accent': t.accent,
    '--accent-press': 'color-mix(in srgb, ' + t.accent + ' 78%, #000)',
    '--font-display': fp.display + ", 'Inter', sans-serif",
    '--font-ui': fp.ui + ", -apple-system, system-ui, sans-serif"
  };
  const cls = 'app theme-' + t.theme + ' density-' + t.density + (t.rail ? ' rail-collapsed' : '');

  const activeNav = route.view === 'category' ? 'browse' : route.view;
  const activeCat = route.view === 'category' ? route.catId : null;

  let body;
  if (route.view === 'dashboard') body = <DashboardView nav={nav} favs={favs} toggleFav={toggleFav} />;
  else if (route.view === 'browse') body = <BrowseView nav={nav} favs={favs} toggleFav={toggleFav} search={search} route={route} key={'browse-' + (route.catId || '') + (route.sort || '') + '-' + version} />;
  else if (route.view === 'category') body = <CategoryView nav={nav} favs={favs} toggleFav={toggleFav} route={route} key={'cat-' + route.catId + '-' + version} />;
  else if (route.view === 'collections') body = <CollectionsView nav={nav} favs={favs} toggleFav={toggleFav} />;
  else if (route.view === 'favorites') body = <FavoritesView nav={nav} favs={favs} toggleFav={toggleFav} />;
  else if (route.view === 'manage') body = <ManageView nav={nav} notify={notify} refresh={refresh} version={version} key={'manage-' + version} />;
  else if (route.view === 'add') body = <AddSectionView nav={nav} route={route} notify={notify} refresh={refresh} key={'add-' + (route.editId || 'new')} />;
  else if (route.view === 'settings') body = <SettingsView nav={nav} route={route} profile={profile} setProfile={setProfile} notify={notify} t={t} setTweak={setTweak} favs={favs} onSignOut={onSignOut} />;
  else if (route.view === 'section') {
    body = window.sectionById(route.sectionId)
      ? <SectionView nav={nav} favs={favs} toggleFav={toggleFav} route={route} notify={notify} refresh={refresh} />
      : <DashboardView nav={nav} favs={favs} toggleFav={toggleFav} />;
  }

  return (
    <div className={cls} style={rootStyle}>
      {/* Sidebar */}
      <aside className="sidebar">
        <div className="sb-brand">
          <img className="sb-logo-full" src={window.assetUrl('app/assets/sectionly-logo.png')} alt="Sectionly" />
          <span className="sb-logo sb-logo-mark">
            <img src={window.assetUrl('app/assets/sectionly-icon.png')} alt="Sectionly" />
          </span>
        </div>

        <div className="sb-scroll">
          {NAV_MAIN.map(n =>
            <button key={n.id} className={'nav-item' + (activeNav === n.id && !activeCat ? ' active' : '')}
              onClick={() => nav({ view: n.id })} title={n.label}>
              <Icon name={n.icon} size={18} />
              <span className="nav-label">{n.label}</span>
              {n.id === 'favorites' && favs.length > 0 && <span className="nav-count">{favs.length}</span>}
            </button>)}

          <button className={'nav-item nav-parent' + (catsOpen ? ' open' : '')}
            onClick={() => setCatsOpen(o => !o)} title="Categories">
            <Icon name="folder" size={18} />
            <span className="nav-label">Categories</span>
            <span className="chev"><Icon name="arrow" size={14} /></span>
          </button>
          {catsOpen && window.CATEGORIES.map(c =>
            <button key={c.id} className={'nav-item nav-sub' + (activeCat === c.id ? ' active' : '')}
              onClick={() => nav({ view: 'category', catId: c.id })} title={c.label}>
              <span className="nav-dot" style={{ background: c.color }} />
              <span className="nav-label">{c.label}</span>
              <span className="nav-count">{window.catCount(c.id)}</span>
            </button>)}
          {catsOpen &&
            <button className="nav-item nav-sub nav-add" title="Add new category">
              <span className="nav-add-plus"><Icon name="plus" size={12} /></span>
              <span className="nav-label">Add New</span>
            </button>}
        </div>

        <div className="sb-foot">
          <div className="sb-user-wrap" ref={userMenuRef}>
            {userMenuOpen &&
              <div className="sb-menu">
                <div className="sb-menu-head"><b>{profile.name}</b><span>{profile.email}</span></div>
                <div className="sb-menu-sep" />
                <button className="sb-menu-item" onClick={() => { setUserMenuOpen(false); nav({ view: 'settings', tab: 'profile' }); }}><Icon name="gear" size={17} /> Settings</button>
                <button className="sb-menu-item" onClick={() => { setUserMenuOpen(false); nav({ view: 'settings', tab: 'account' }); }}><Icon name="user" size={17} /> Account</button>
                <div className="sb-menu-sep" />
                <button className="sb-menu-item danger" onClick={() => { setUserMenuOpen(false); onSignOut(); }}><Icon name="logout" size={17} /> Sign out</button>
              </div>}
            <button className={'sb-user' + (userMenuOpen || route.view === 'settings' ? ' active' : '')} onClick={() => setUserMenuOpen(o => !o)} title="Account menu">
              <span className="avatar">{profile.avatar ? <img src={window.assetUrl(profile.avatar)} alt={profile.name} /> : initials(profile.name)}</span>
              <div className="sb-user-meta"><b>{profile.name}</b><span>{profile.email}</span></div>
              <Icon name="arrow" size={16} />
            </button>
          </div>
        </div>
      </aside>

      {/* Main */}
      <div className="main">
        <header className="topbar">
          <button className="rail-toggle" onClick={() => setTweak('rail', !t.rail)} title="Toggle sidebar">
            <Icon name="panel" size={17} />
          </button>
          <div className="search">
            <Icon name="search" size={17} />
            <input ref={searchRef} value={search} onChange={e => onSearch(e.target.value)}
              placeholder="Search sections, tags, categories…" />
            <span className="kbd">⌘K</span>
          </div>
          <span className="top-spacer" />
          <button className="icon-btn" onClick={() => setTweak('theme', t.theme === 'light' ? 'dark' : 'light')} title="Toggle theme">
            <Icon name={t.theme === 'light' ? 'moon' : 'sun'} size={18} />
          </button>
          <div className="notif-wrap" ref={notifRef}>
            <button className={'icon-btn' + (notifOpen ? ' active' : '')} title="Notifications" onClick={() => setNotifOpen(o => !o)}><Icon name="bell" size={18} /></button>
            {notifOpen && (
              <div className="notif-panel">
                <div className="notif-head">Notifications</div>
                <div className="notif-empty">
                  <span className="notif-empty-ico"><Icon name="bell" size={22} /></span>
                  <p className="notif-empty-title">No notifications yet</p>
                  <p className="notif-empty-sub">You’re all caught up. New activity will show up here.</p>
                </div>
              </div>
            )}
          </div>
          <button className="btn btn-primary btn-plus" onClick={() => nav({ view: 'add' })} title="Add new section" aria-label="Add new section">
            <Icon name="plus" size={18} />
          </button>
        </header>

        <main className="content">
          {body}
        </main>
      </div>

      {/* Tweaks */}
      <TweaksPanel>
        <TweakSection label="Brand accent" />
        <TweakColor label="Accent color" value={t.accent}
          options={['#6243EB', '#1a7fff', '#10b981', '#f97316', '#ec4899', '#8b5cf6']}
          onChange={v => setTweak('accent', v)} />
        <TweakSection label="Typography" />
        <TweakRadio label="Font pairing" value={t.fontPair}
          options={['modern', 'geometric', 'playful']}
          onChange={v => setTweak('fontPair', v)} />
        <TweakSection label="Layout" />
        <TweakRadio label="Card density" value={t.density}
          options={['compact', 'regular', 'comfy']}
          onChange={v => setTweak('density', v)} />
        <TweakToggle label="Collapse sidebar" value={t.rail} onChange={v => setTweak('rail', v)} />
        <TweakSection label="Theme" />
        <TweakRadio label="App theme" value={t.theme}
          options={['light', 'dark']}
          onChange={v => setTweak('theme', v)} />
      </TweaksPanel>
      <Toast msg={toast && toast.msg} error={toast && toast.error} />
    </div>
  );
}

/* Boot persistence (server when deployed, localStorage otherwise) THEN render.
   Gating the render on the async load means the very first paint already has
   the real data — no flash of defaults, no race with localStorage. */
function Root() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [user, setUser] = useState(() => window.Auth.currentUser());
  useEffect(() => window.Auth.onChange(setUser), []);

  const onSignOut = useCallback(() => { window.Auth.signOut(); }, []);

  const fp = FONT_PAIRS[t.fontPair] || FONT_PAIRS.modern;
  const rootStyle = {
    '--accent': t.accent,
    '--accent-press': 'color-mix(in srgb, ' + t.accent + ' 78%, #000)',
    '--font-display': fp.display + ", 'Inter', sans-serif",
    '--font-ui': fp.ui + ", -apple-system, system-ui, sans-serif"
  };

  if (!user) {
    return (
      <div className={'theme-' + t.theme} style={Object.assign({ height: '100%' }, rootStyle)}>
        <AuthApp
          theme={t.theme}
          toggleTheme={() => setTweak('theme', t.theme === 'light' ? 'dark' : 'light')}
          onAuthed={setUser} />
      </div>
    );
  }
  return <App user={user} onSignOut={onSignOut} />;
}

/* Boot persistence first, THEN auth (it reuses the detected server/local mode),
   THEN render — so the first paint already reflects the real session + data. */
window.Store.boot(function (mode) {
  if (window.SectionStore && window.SectionStore.recompose) window.SectionStore.recompose();
  window.Auth.boot(mode, function () {
    ReactDOM.createRoot(document.getElementById('root')).render(<Root />);
  });
});
