// Top-level app shell + tweaks panel
const { useState, useEffect } = React;

// Bumped on every meaningful update so we can see what's live in the preview.
// Convention: x.y.z — patch on tweaks, minor on new screens/sections, major on
// a wholesale UX shift.
const APP_VERSION = 'v1.10.0';
const APP_VERSION_DATE = '3 May 2026';

const VersionBadge = () => (
  <div
    title={`Last updated ${APP_VERSION_DATE}`}
    style={{
      position: 'fixed', bottom: 12, right: 12, zIndex: 250,
      display: 'inline-flex', alignItems: 'center', gap: 6,
      padding: '5px 10px', borderRadius: 99,
      background: 'color-mix(in oklab, var(--surface) 92%, transparent)',
      backdropFilter: 'blur(6px)',
      border: '1px solid var(--border)',
      color: 'var(--text-muted)',
      fontSize: 10.5, fontFamily: 'JetBrains Mono, monospace',
      fontVariantNumeric: 'tabular-nums',
      boxShadow: '0 4px 12px rgba(15,23,42,0.06)',
      pointerEvents: 'auto', userSelect: 'none',
    }}
  >
    <span style={{
      width: 6, height: 6, borderRadius: '50%',
      background: 'var(--positive)',
      boxShadow: '0 0 0 3px color-mix(in oklab, var(--positive) 18%, transparent)',
    }}/>
    <span>{APP_VERSION}</span>
    <span style={{ color: 'var(--text-faint)' }}>·</span>
    <span>{APP_VERSION_DATE}</span>
  </div>
);

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "theme": "light",
  "primary": "#2563eb",
  "radius": 25,
  "density": "default",
  "sparkStyle": "line",
  "sidebarExpanded": true
}/*EDITMODE-END*/;

const PRIMARY_PRESETS = [
  { name: 'Blue',    value: '#2563eb' },
  { name: 'Indigo',  value: '#4f46e5' },
  { name: 'Violet',  value: '#7c3aed' },
  { name: 'Pink',    value: '#db2777' },
  { name: 'Emerald', value: '#059669' },
  { name: 'Amber',   value: '#d97706' },
  { name: 'Slate',   value: '#0f172a' },
];

function App() {
  const [tweaks, setTweak] = useTweaks(TWEAK_DEFAULTS);

  // Auth mode: 'login' (picker) | 'client' (real client) | 'am' (AM portal).
  // When mode is 'am' and amClientId is set, AM has drilled into a client and
  // we render the client portal with an AM ribbon overlay.
  const [authMode, setAuthMode] = useState(() => {
    try { return localStorage.getItem('clicky_auth_mode') || 'login'; }
    catch (e) { return 'login'; }
  });
  const [amClientId, setAmClientId] = useState(() => {
    try { return localStorage.getItem('clicky_am_client') || null; }
    catch (e) { return null; }
  });
  // Which AM screen to land on after exiting client-view (set by AmRail).
  const [amScreenIntent, setAmScreenIntent] = useState('portfolio');
  // AM client-setup overlay (gear icon in ribbon).
  const [amSetupOpen, setAmSetupOpen] = useState(false);

  // Sync window.CLIENT to the active brand synchronously so the first
  // render after a refresh already reads the right shortName/name. The
  // swap helper is idempotent — safe to call every render.
  if (window.swapActiveClient) {
    window.swapActiveClient(authMode === 'am' && amClientId ? amClientId : null);
  }

  const handleLogin = (mode) => {
    setAuthMode(mode);
    try { localStorage.setItem('clicky_auth_mode', mode); } catch(e){}
  };
  const handleSignOut = () => {
    setAuthMode('login');
    setAmClientId(null);
    try {
      localStorage.setItem('clicky_auth_mode', 'login');
      localStorage.removeItem('clicky_am_client');
    } catch(e){}
  };
  const enterClientAsAm = (id) => {
    setAmClientId(id);
    try { localStorage.setItem('clicky_am_client', id); } catch(e){}
  };
  const exitToPortfolio = () => {
    setAmClientId(null);
    try { localStorage.removeItem('clicky_am_client'); } catch(e){}
  };

  // Hash-based routing — initial hash, if present, wins over the default.
  // Compatible with static http.server (no SPA rewrite required) and the
  // hash visibly changes as the user navigates between sections.
  const initialHashSection = (() => {
    try {
      const fromHash = (window.location.hash || '').replace(/^#\/?/, '').split('?')[0];
      return fromHash || null;
    } catch (e) { return null; }
  })();
  // User-chosen default dashboard ('classic' | 'ai-led'). Falls back to
  // the standard dashboard. Hash always wins over preference.
  const initialActiveSection = (() => {
    if (initialHashSection) return initialHashSection;
    try {
      const pref = localStorage.getItem('clicky_default_dashboard');
      if (pref === 'ai-led') return 'dashboard-v2';
    } catch (e) {}
    return 'dashboard';
  })();
  const [active, setActive] = useState(initialActiveSection);
  const [billingTab, setBillingTab] = useState(null);
  const goBilling = (tab) => { setBillingTab(tab || 'invoices'); setActive('billing'); };
  const [contractDetailId, setContractDetailId] = useState(null);
  const openContractDetail = (id) => { setContractDetailId(id); setActive('contract-detail'); };
  const [channelsExpanded, setChannelsExpanded] = useState(true);
  const [kpiDetailKey, setKpiDetailKey] = useState(null);
  const openKpiDetail = (key) => { setKpiDetailKey(key); setActive('kpi-detail'); };
  const [maintenanceSiteId, setMaintenanceSiteId] = useState(null);
  const openMaintenance = (siteId) => { setMaintenanceSiteId(siteId || null); setActive('maintenance'); };
  const [requestKpiOpen, setRequestKpiOpen] = useState(false);
  const openRequestKpi = () => setRequestKpiOpen(true);
  const [insiderArticleId, setInsiderArticleId] = useState(null);
  const openInsiderArticle = (id) => { setInsiderArticleId(id); setActive('insider'); };
  const [searchQuery, setSearchQuery] = useState('');
  // Ask ClickyAI lightbox — opens from any "Ask ClickyAI" rainbow button.
  const [askLightboxOpen, setAskLightboxOpen] = useState(false);
  const [askInitialQuery, setAskInitialQuery] = useState(null);
  const openAskLightbox = () => setAskLightboxOpen(true);
  const submitAskFromLightbox = (query) => {
    setAskInitialQuery(query);
    setAskLightboxOpen(false);
    setActive('ask');
  };
  // Allow the lightbox's "Open full Ask page" link (which lives outside React's
  // prop tree because it dispatches a window event) to drive the same flow.
  useEffect(() => {
    const handler = () => setActive('ask');
    window.addEventListener('clicky:openAskFull', handler);
    return () => window.removeEventListener('clicky:openAskFull', handler);
  }, []);

  // Sync the active section to the URL hash — keep it visibly changing
  // as users browse. pushState fires no event so we don't loop with the
  // hashchange listener below; that listener only fires from real
  // navigation (back/forward, manual edit).
  useEffect(() => {
    if (authMode === 'login') return;
    if (authMode === 'am' && !amClientId) return; // AM portfolio owns its own nav
    const next = '#/' + active;
    if (window.location.hash !== next) {
      try { window.history.pushState({ active }, '', next); } catch (e) {}
    }
  }, [active, authMode, amClientId]);

  useEffect(() => {
    const handler = () => {
      const fromHash = (window.location.hash || '').replace(/^#\/?/, '').split('?')[0];
      if (fromHash && fromHash !== active) setActive(fromHash);
    };
    window.addEventListener('hashchange', handler);
    window.addEventListener('popstate', handler);
    return () => {
      window.removeEventListener('hashchange', handler);
      window.removeEventListener('popstate', handler);
    };
  }, [active]);
  const onSearchJump = (target, opts) => {
    setSearchQuery('');
    if (target === 'cpts' && opts?.kpi) { setKpiDetailKey(opts.kpi); setActive('kpi-detail'); return; }
    if (target === 'maintenance' && opts?.siteId) { setMaintenanceSiteId(opts.siteId); setActive('maintenance'); return; }
    if (target === 'billing' && opts?.tab) { goBilling(opts.tab); return; }
    if (target === 'insider' && opts?.articleId) { openInsiderArticle(opts.articleId); return; }
    setActive(target);
  };

  // Apply tweaks to :root
  useEffect(() => {
    document.documentElement.setAttribute('data-theme', tweaks.theme);
    document.documentElement.style.setProperty('--primary', tweaks.primary);
    document.documentElement.style.setProperty('--radius', tweaks.radius + 'px');
    // density mapping
    const dMap = { compact: 0.85, default: 1, comfortable: 1.15 };
    document.documentElement.style.setProperty('--density', dMap[tweaks.density] || 1);
    // also persist quick theme + primary so initial paint matches
    try {
      localStorage.setItem('amplify_tweaks', JSON.stringify({ theme: tweaks.theme, primary: tweaks.primary }));
    } catch(e) {}
  }, [tweaks]);

  const toggleTheme = () => setTweak('theme', tweaks.theme === 'dark' ? 'light' : 'dark');

  const screen = (() => {
    switch (active) {
      case 'dashboard': return <DashboardScreen setActive={setActive} openKpiDetail={openKpiDetail} goBilling={goBilling} openInsiderArticle={openInsiderArticle} openAskLightbox={openAskLightbox} />;
      case 'dashboard-v2': return <DashboardV2Screen setActive={setActive} openKpiDetail={openKpiDetail} goBilling={goBilling} openInsiderArticle={openInsiderArticle} openAskLightbox={openAskLightbox} />;
      case 'channels':  return <ChannelsScreen setActive={setActive} />;
      case 'paid-media': return <PaidMediaScreen setActive={setActive} openAskLightbox={openAskLightbox} />;
      case 'add-paid-media': return <AddPaidMediaChannelsScreen setActive={setActive} />;
      case 'add-seo':         return <AddSeoScreen setActive={setActive} />;
      case 'add-maintenance': return <AddMaintenanceScreen setActive={setActive} />;
      case 'google':    return <GoogleAdsScreen sparkStyle={tweaks.sparkStyle} />;
      case 'meta':      return <MetaAdsScreen sparkStyle={tweaks.sparkStyle} />;
      case 'seo':       return <SeoScreen sparkStyle={tweaks.sparkStyle} />;
      case 'reports':   return <ReportsScreen />;
      case 'tickets':   return <TicketsScreen />;
      case 'billing':   return <BillingScreen initialTab={billingTab} openContractDetail={openContractDetail} setActive={setActive} />;
      case 'contract-detail': return <ContractDetailScreen contractId={contractDetailId} onBack={() => { setBillingTab('contracts'); setActive('billing'); }} setActive={setActive} />;
      case 'ask':       return <AskScreen initialQuery={askInitialQuery} onQueryConsumed={() => setAskInitialQuery(null)} />;
      case 'events':    return <EventsScreen />;
      case 'insider':   return <InsiderScreen initialArticleId={insiderArticleId} clearInitialArticle={() => setInsiderArticleId(null)} />;
      case 'growth':    return <GrowthScreen setActive={setActive} />;
      case 'files':     return <FilesScreen />;
      case 'kpi-detail':return <KpiDetailScreen kpiKey={kpiDetailKey} onBack={() => setActive('dashboard')} setActive={setActive} />;
      case 'cpts':      return <CptsIndexScreen setActive={setActive} openKpiDetail={openKpiDetail} openRequestKpi={openRequestKpi} />;
      case 'maintenance': return <MaintenanceScreen siteId={maintenanceSiteId} setSiteId={setMaintenanceSiteId} setActive={setActive} />;
      case 'team':      return <TeamScreen />;
      case 'opportunities': return <GrowthOpportunitiesScreen setActive={setActive} openAskLightbox={openAskLightbox} />;
      case 'insights':  return <WholeAccountInsightsScreen setActive={setActive} openAskLightbox={openAskLightbox} />;
      default:          return null;
    }
  })();

  const screenLabel = ({
    'dashboard-v2': '00 Dashboard (ClickyAI View)',
    dashboard: '01 Dashboard',
    channels:  '02 My Ad Channels',
    'paid-media': '02a Paid Media',
    'add-paid-media': '02b Add Paid Media Channels',
    'add-seo':        '02c Add SEO',
    'add-maintenance':'02d Add Maintenance',
    google:    '02b Google Ads',
    meta:      '02d Meta Ads',
    seo:       '02c SEO',
    reports:   '03 My Reports',
    tickets:   '04 Support Tickets',
    billing:   '05 Contracts & Billing',
    'contract-detail': '05a Contract detail',
    ask:       '06 ClickyAI™',
    events:    '08 Events',
    insider:   '08b Clicky Insider',
    growth:    '09 Growth',
    files:     '10 Files',
    'kpi-detail': '11 KPI Detail',
    cpts:      '12 All Performance Targets',
    maintenance: '13 Website Maintenance Pro',
    team:      '14 Your Team',
    opportunities: '15 Growth Opportunities',
    insights:  '16 Account Insights',
  })[active];

  // Page titles in the browser tab — "Clicky | Current page | Enterprise
  // PRO Client Portal". Strips the leading numeric prefix from screenLabel
  // so the chrome reads naturally rather than "01 Dashboard". Login + AM
  // modes get their own title.
  useEffect(() => {
    const SUFFIX = 'Enterprise PRO Client Portal';
    let pageName = 'Dashboard';
    if (authMode === 'login') {
      pageName = 'Sign in';
    } else if (authMode === 'am' && !amClientId) {
      pageName = 'Account Manager';
    } else {
      pageName = (screenLabel || active || 'Dashboard').replace(/^\d+[a-z]*\s+/, '');
    }
    document.title = `Clicky | ${pageName} | ${SUFFIX}`;
  }, [active, authMode, amClientId, screenLabel]);

  // Auth gates — short-circuit before rendering the client portal.
  if (authMode === 'login') {
    return <><LoginScreen onLogin={handleLogin} /><VersionBadge /></>;
  }
  if (authMode === 'am' && !amClientId) {
    return <><AmPortal onSignOut={handleSignOut} onOpenClient={enterClientAsAm} initialActive={amScreenIntent} /><VersionBadge /></>;
  }

  const isAmViewing = authMode === 'am' && amClientId;
  const goAmPortfolio = () => { setAmSetupOpen(false); setAmScreenIntent('portfolio'); exitToPortfolio(); };
  const goAmThisWeek  = () => { setAmSetupOpen(false); setAmScreenIntent('thisweek');  exitToPortfolio(); };

  return (
    <div style={{ display: 'flex', minHeight: '100vh' }} data-screen-label={screenLabel}>
      {isAmViewing && (
        <AmRail
          currentClientId={amClientId}
          onBackToPortfolio={goAmPortfolio}
          onGoThisWeek={goAmThisWeek}
          onSignOut={handleSignOut}
        />
      )}
      <div style={{ display: 'flex', flex: 1, minWidth: 0, flexDirection: 'column' }}>
      {isAmViewing && (
        <AmRibbon
          clientId={amClientId}
          onBack={goAmPortfolio}
          onSwitchClient={(id) => { setAmSetupOpen(false); enterClientAsAm(id); }}
          onOpenSetup={() => setAmSetupOpen(v => !v)}
          setupOpen={amSetupOpen}
        />
      )}
      <div style={{ display: 'flex', flex: 1, minHeight: 0 }}>
      <Sidebar active={active} setActive={(id) => { if (amSetupOpen) setAmSetupOpen(false); setActive(id); }}
               channelsExpanded={channelsExpanded} setChannelsExpanded={setChannelsExpanded}
               density={tweaks.density}
               openKpiDetail={openKpiDetail}
               activeKpiKey={active === 'kpi-detail' ? kpiDetailKey : null}
               openMaintenance={openMaintenance}
               activeSiteId={active === 'maintenance' ? maintenanceSiteId : null}
               openRequestKpi={openRequestKpi}
               goBilling={goBilling}
               billingTab={active === 'billing' ? billingTab : null} />

      <main style={{ flex: 1, minWidth: 0, display: 'flex', flexDirection: 'column' }}>
        <Topbar
          onToggleTheme={toggleTheme}
          theme={tweaks.theme}
          searchQuery={searchQuery}
          setSearchQuery={setSearchQuery}
          onSearchClose={() => setSearchQuery('')}
          openAskLightbox={openAskLightbox}
          setActive={setActive}
        />
        {isAmViewing && amSetupOpen ? (
          <div style={{ flex: 1, minHeight: 0 }}>
            <AmClientSetupScreen
              clientId={amClientId}
              onClose={() => setAmSetupOpen(false)}
            />
          </div>
        ) : (
          <div style={{
            padding: '28px 32px', maxWidth: 1480, width: '100%', margin: '0 auto', flex: 1,
            filter: searchQuery ? 'blur(3px) saturate(0.8)' : 'none',
            transition: 'filter 180ms ease',
            pointerEvents: searchQuery ? 'none' : 'auto',
          }}>
            {screen}
          </div>
        )}
      </main>
      </div>

      {searchQuery && <SearchOverlay query={searchQuery} onClose={() => setSearchQuery('')} onJump={onSearchJump} />}
      {requestKpiOpen && <RequestPerformanceTargetModal onClose={() => setRequestKpiOpen(false)} />}
      {askLightboxOpen && <AskAnythingLightbox onClose={() => setAskLightboxOpen(false)} onSubmit={submitAskFromLightbox} />}

      <TweaksPanel>
        <TweakSection title="Appearance">
          <TweakRadio label="Theme" value={tweaks.theme}
            options={[{value:'light',label:'Light'},{value:'dark',label:'Dark'}]}
            onChange={v => setTweak('theme', v)} />
          <div style={{ marginTop: 8 }}>
            <div style={{ fontSize: 11, fontWeight: 600, color: 'var(--tw-muted, #999)', marginBottom: 6, textTransform: 'uppercase', letterSpacing: '0.04em' }}>Primary</div>
            <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
              {PRIMARY_PRESETS.map(p => (
                <button key={p.value} onClick={() => setTweak('primary', p.value)} title={p.name} style={{
                  width: 28, height: 28, borderRadius: 6, background: p.value,
                  border: tweaks.primary === p.value ? '2px solid #fff' : '2px solid transparent',
                  outline: tweaks.primary === p.value ? '2px solid ' + p.value : 'none',
                  cursor: 'pointer', transition: 'transform 0.1s',
                }}/>
              ))}
            </div>
          </div>
        </TweakSection>

        <TweakSection title="Layout">
          <TweakSlider label="Border radius" value={tweaks.radius} min={0} max={32} step={1}
            onChange={v => setTweak('radius', v)} unit="px" />
          <TweakRadio label="Density" value={tweaks.density}
            options={[{value:'compact',label:'Compact'},{value:'default',label:'Default'},{value:'comfortable',label:'Comfy'}]}
            onChange={v => setTweak('density', v)} />
        </TweakSection>

        <TweakSection title="Data">
          <TweakRadio label="Sparkline style" value={tweaks.sparkStyle}
            options={[{value:'line',label:'Line'},{value:'area',label:'Area'},{value:'bar',label:'Bar'}]}
            onChange={v => setTweak('sparkStyle', v)} />
        </TweakSection>

        <TweakSection title="Navigate">
          <div style={{ display: 'grid', gap: 6 }}>
            {[
              { id: 'dashboard', label: 'Dashboard' },
              { id: 'google',    label: 'Google Ads' },
              { id: 'reports',   label: 'My Reports' },
              { id: 'tickets',   label: 'Support Tickets' },
              { id: 'billing',   label: 'Contracts & Billing' },
              { id: 'ask',       label: 'ClickyAI™' },
            ].map(s => (
              <button key={s.id} onClick={() => setActive(s.id)} style={{
                padding: '6px 10px', textAlign: 'left',
                background: active === s.id ? 'rgba(255,255,255,0.08)' : 'transparent',
                color: active === s.id ? '#fff' : '#bbb',
                border: '1px solid rgba(255,255,255,0.08)', borderRadius: 6, fontSize: 12, cursor: 'pointer',
              }}>{s.label}</button>
            ))}
          </div>
        </TweakSection>
      </TweaksPanel>
      </div>
      <VersionBadge />
    </div>
  );
}

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