// App shell: left rail + top bar + router

const { useState: useS0 } = React;

const NAV = [
  { id: 'home',          label: 'Home',          icon: 'Home' },
  { id: 'chat',          label: 'Chat',          icon: 'Chat',     badge: 'new' },
  { id: 'connectors',    label: 'Connectors',    icon: 'Plug' },
  { id: 'fabric',        label: 'Fabric',        icon: 'Graph' },
  { id: 'learning',      label: 'Learning',      icon: 'Sparkle',  live: true },
  { id: 'api',           label: 'API',           icon: 'Code' },
  { id: 'observability', label: 'Observability', icon: 'Activity' },
];

// Single source of truth for "does this route have a nav entry".
// index.html routes off the same predicate, so a panel can never be reachable
// without a way back to it — flip a flag in NAV above and both follow.
// `hidden: true` retires a panel outright while keeping its code in the build.
function navVisible(id) {
  const item = NAV.find(i => i.id === id);
  return !!item && !item.hidden;
}

// Where the console lands when it has nothing valid to restore: after sign-in,
// on a first load, and whenever the guard has to rewrite an unreachable route.
function defaultRoute() {
  return navVisible('chat') ? 'chat' : 'connectors';
}

function Rail({ route, setRoute, collapsed, setCollapsed, onboarding, startOnboarding, session, onLogout }) {
  const navItems = NAV.filter(item => navVisible(item.id));
  const acct = session && session.account;
  const brand = parcleBrand();
  // Workspace identity: on a branded deploy the org workspace IS the customer,
  // so it carries their name whether or not a session is open. Unbranded, it
  // keeps the generic labels it had before branding existed.
  // Signed out, the subtitle is the customer's domain — but only when a brand
  // actually names one. Unbranded it would fall through to `parcle.ai`, i.e.
  // the vendor's domain presented as the workspace's, so show nothing instead.
  const wsName = parcleWorkspaceName('Organization');
  const wsSub  = acct ? acct.email : (brand.configured ? brand.domain : '');
  // Signed out (mock mode only — a configured apiBase gates the app behind
  // LoginGate). There is no demo persona to stand in for the real account:
  // an invented name and address here would be indistinguishable from a real
  // signed-in user, so say plainly that nobody is signed in.
  const userName = acct ? (acct.email || '').split('@')[0] : 'Not signed in';
  const userSub  = acct ? acct.email : 'Mock mode · no session';
  const userInitials = acct ? (acct.email || '?').slice(0, 2).toUpperCase() : '—';
  return (
    <aside style={{
      width: collapsed ? 56 : 240,
      flexShrink: 0,
      borderRight: '1px solid var(--border-subtle)',
      background: 'var(--bg)',
      display: 'flex', flexDirection: 'column',
      transition: 'width 160ms cubic-bezier(.2,.8,.2,1)',
      overflow: 'hidden',
    }}>
      {/* Org switcher */}
      <div style={{ padding: collapsed ? '12px 8px' : '14px 12px', borderBottom: '1px solid var(--border-subtle)' }}>
        <button style={{
          width: '100%', display: 'flex', alignItems: 'center',
          gap: 10, padding: collapsed ? 6 : '6px 8px',
          borderRadius: 8,
          background: 'transparent',
        }}>
          <BrandMark size={24} radius={6}/>
          {!collapsed && (
            <>
              <div style={{ flex: 1, textAlign: 'left', minWidth: 0 }}>
                <div style={{ fontSize: 13, fontWeight: 500 }}>{wsName}</div>
                {wsSub && <div className="mono-sm mono text-tertiary" style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{wsSub}</div>}
              </div>
              <Icons.ChevronD size={12} style={{ color: 'var(--text-tertiary)' }}/>
            </>
          )}
        </button>
      </div>

      {/* Nav */}
      <nav style={{ flex: 1, padding: 8, display: 'flex', flexDirection: 'column', gap: 1 }}>
        {navItems.map(item => {
          const Icon = Icons[item.icon];
          const active = route === item.id;
          return (
            <button key={item.id}
              onClick={() => setRoute(item.id)}
              style={{
                display: 'flex', alignItems: 'center', gap: 10,
                height: 32, padding: collapsed ? 0 : '0 10px',
                justifyContent: collapsed ? 'center' : 'flex-start',
                borderRadius: 7,
                background: active ? 'var(--selected)' : 'transparent',
                color: active ? 'var(--text-primary)' : 'var(--text-secondary)',
                fontSize: 13, fontWeight: active ? 500 : 400,
                position: 'relative',
              }}
              onMouseEnter={e => { if (!active) e.currentTarget.style.background = 'var(--hover)'; }}
              onMouseLeave={e => { if (!active) e.currentTarget.style.background = 'transparent'; }}
            >
              <Icon size={16} style={{ flexShrink: 0 }} />
              {!collapsed && <span style={{ flex: 1, textAlign: 'left' }}>{item.label}</span>}
              {!collapsed && item.count != null && (
                <span className="mono-sm mono" style={{
                  padding: '1px 6px', borderRadius: 4,
                  background: 'var(--accent-muted)', color: 'var(--accent-text)',
                  fontSize: 11, lineHeight: '16px'
                }}>{item.count}</span>
              )}
              {!collapsed && item.badge === 'new' && (
                <span style={{
                  padding: '1px 5px', borderRadius: 3,
                  background: 'var(--accent)', color: 'var(--on-accent)',
                  fontSize: 9, fontWeight: 600, letterSpacing: '0.04em',
                }}>NEW</span>
              )}
              {!collapsed && item.live && (
                <span style={{
                  width: 6, height: 6, borderRadius: '50%',
                  background: 'var(--success)',
                  animation: 'parclePulseLoop 2s ease-out infinite',
                }}/>
              )}
            </button>
          );
        })}
      </nav>

      {/* Onboarding / Bottom. The setup guide is demo scaffolding — its vendor
          grid, "Available" workspace URL and OAuth rows are all invented — so
          the only entry point to it is hidden once a backend is configured.
          Without this gate a customer evaluating against their own data is one
          click away from a screen full of fixtures. */}
      {!collapsed && !onboarding && !parcleApiBase() && (
        <div style={{ padding: 12, borderTop: '1px solid var(--border-subtle)' }}>
          <button onClick={startOnboarding} className="btn sm" style={{ width: '100%', justifyContent: 'flex-start', fontSize: 12 }}>
            <Icons.Sparkle size={13} /> Finish setup
          </button>
        </div>
      )}
      <div style={{ padding: collapsed ? 8 : 12, borderTop: '1px solid var(--border-subtle)', display: 'flex', alignItems: 'center', gap: 10, justifyContent: collapsed ? 'center' : 'flex-start' }}>
        <div style={{
          width: 24, height: 24, borderRadius: '50%',
          background: 'linear-gradient(135deg, var(--accent), var(--accent-hover))',
          color: 'var(--on-accent)', flexShrink: 0,
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          fontSize: 10, fontWeight: 600,
        }}>{userInitials}</div>
        {!collapsed && (
          <>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontSize: 12, fontWeight: 500, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{userName}</div>
              <div className="mono-sm mono text-tertiary" style={{ fontSize: 11, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{userSub}</div>
            </div>
            {acct && onLogout && (
              <button className="btn sm ghost" onClick={onLogout} title="Sign out">
                <Icons.LogOut size={12}/>
              </button>
            )}
            <button className="btn sm ghost" onClick={() => setCollapsed(true)} title="Collapse">
              <Icons.ChevronL size={12}/>
            </button>
          </>
        )}
        {collapsed && (
          <button className="btn sm ghost" style={{ position: 'absolute', bottom: 8, left: 60, zIndex: 2 }} onClick={() => setCollapsed(false)}>
            <Icons.ChevronR size={12}/>
          </button>
        )}
      </div>
    </aside>
  );
}

function TopBar({ route, setRoute, env, setEnv, setCmdOpen }) {
  const breadcrumb = {
    home: ['Home'],
    chat: ['Chat'],
    connectors: ['Connectors'],
    fabric: ['Fabric', parcleWorkspaceName('Organization')],
    learning: ['Learning stream'],
    api: ['API', 'Reference'],
    // No second crumb: the Retrievals/Usage tab state lives inside the page.
    observability: ['Observability'],
  }[route] || ['Home'];
  return (
    <header style={{
      height: 48, flexShrink: 0,
      borderBottom: '1px solid var(--border-subtle)',
      background: 'var(--bg)',
      display: 'flex', alignItems: 'center',
      padding: '0 24px', gap: 12,
      position: 'sticky', top: 0, zIndex: 10,
    }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 13, whiteSpace: 'nowrap', flexShrink: 0 }}>
        {breadcrumb.map((b, i) => (
          <React.Fragment key={i}>
            {i > 0 && <span className="text-tertiary" style={{ fontSize: 11 }}>/</span>}
            <span style={{ color: i === breadcrumb.length - 1 ? 'var(--text-primary)' : 'var(--text-secondary)', fontWeight: i === breadcrumb.length - 1 ? 500 : 400 }}>{b}</span>
          </React.Fragment>
        ))}
      </div>

      <div style={{ flex: 1 }} />

      <div className="topbar-ticker-wrap">
        <LearningTicker setRoute={setRoute}/>
      </div>

      <button onClick={() => setCmdOpen(true)} className="topbar-search" style={{
        display: 'flex', alignItems: 'center', gap: 8,
        height: 30, padding: '0 10px',
        border: '1px solid var(--border-subtle)', borderRadius: 7,
        background: 'var(--surface)',
        color: 'var(--text-tertiary)',
        fontSize: 12,
      }}>
        <Icons.Search size={13}/>
        <span style={{ flex: 1, textAlign: 'left' }}>Jump to…</span>
        <span className="kbd">⌘K</span>
      </button>

      <div className="segmented">
        <button className={env === 'dev' ? 'active' : ''} onClick={() => setEnv('dev')}>dev</button>
        <button className={env === 'prod' ? 'active' : ''} onClick={() => setEnv('prod')}>prod</button>
      </div>

      <button className="btn sm ghost" style={{ position: 'relative' }}>
        <Icons.Bell size={14}/>
        <span style={{ position: 'absolute', top: 4, right: 4, width: 6, height: 6, borderRadius: '50%', background: 'var(--accent)' }}/>
      </button>
    </header>
  );
}

// Command-K palette — lightweight
function CmdPalette({ open, onClose, setRoute }) {
  if (!open) return null;
  // Navigation only. This palette used to also list "Entities" (an org, a
  // person, a deal) and "Docs" rows, but those named records that do not exist
  // and jumped to a page rather than opening anything — a search box that
  // answers with invented results is worse than one that only navigates.
  // Searching the real graph belongs here eventually; it needs a backend query,
  // not a hardcoded list.
  const workspace = parcleWorkspaceName('Organization');
  const allItems = [
    { group: 'Jump to', icon: 'Home',     label: 'Home',              route: 'home' },
    { group: 'Jump to', icon: 'Chat',     label: 'Chat',              route: 'chat' },
    { group: 'Jump to', icon: 'Plug',     label: 'Connectors',        route: 'connectors' },
    { group: 'Jump to', icon: 'Graph',    label: `Fabric · ${workspace}`, route: 'fabric' },
    { group: 'Jump to', icon: 'Sparkle',  label: 'Learning stream',   route: 'learning' },
    { group: 'Jump to', icon: 'Code',     label: 'API Reference',     route: 'api' },
    { group: 'Jump to', icon: 'Activity', label: 'Observability',     route: 'observability' },
    { group: 'Actions', icon: 'Plus',     label: 'Add connector',     route: 'connectors' },
  ];
  // Drop entries pointing at panels the nav doesn't expose — the router
  // would bounce them to Connectors, which reads as a broken menu item.
  const items = allItems.filter(i => navVisible(i.route));
  const groups = [...new Set(items.map(i => i.group))];
  return (
    <div onClick={onClose} style={{
      position: 'fixed', inset: 0, background: 'rgba(0,0,0,.4)', zIndex: 100,
      display: 'flex', alignItems: 'flex-start', justifyContent: 'center',
      paddingTop: '15vh',
    }}>
      <div onClick={e => e.stopPropagation()} style={{
        width: 600, background: 'var(--surface-raised)',
        border: '1px solid var(--border)',
        borderRadius: 12, boxShadow: 'var(--shadow-2)',
        overflow: 'hidden'
      }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '0 16px', height: 48, borderBottom: '1px solid var(--border-subtle)' }}>
          <Icons.Search size={14} style={{ color: 'var(--text-tertiary)' }}/>
          <input autoFocus placeholder="Jump to a panel…" style={{
            flex: 1, border: 'none', outline: 'none', background: 'transparent',
            fontSize: 14, color: 'var(--text-primary)',
          }}/>
          <span className="kbd">ESC</span>
        </div>
        <div style={{ maxHeight: 360, overflowY: 'auto', padding: 8 }}>
          {groups.map(g => (
            <div key={g} style={{ marginBottom: 8 }}>
              <div className="t-micro text-tertiary" style={{ padding: '6px 8px' }}>{g}</div>
              {items.filter(i => i.group === g).map((i, idx) => {
                const I = Icons[i.icon];
                return (
                  <button key={idx}
                    onClick={() => { setRoute(i.route); onClose(); }}
                    style={{
                      width: '100%', display: 'flex', alignItems: 'center', gap: 10,
                      padding: '8px 10px', borderRadius: 6, fontSize: 13,
                      color: 'var(--text-primary)',
                    }}
                    onMouseEnter={e => e.currentTarget.style.background = 'var(--hover)'}
                    onMouseLeave={e => e.currentTarget.style.background = 'transparent'}
                  >
                    <I size={14} style={{ color: 'var(--text-secondary)' }}/>
                    <span style={{ flex: 1, textAlign: 'left' }}>{i.label}</span>
                    <Icons.ArrowR size={12} style={{ color: 'var(--text-tertiary)' }}/>
                  </button>
                );
              })}
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { Rail, TopBar, CmdPalette, navVisible, defaultRoute });
