// ─── Janus 主应用 v2：路由栈 + Sheet 层 + 状态存储 ───
const { useState: useSA, useEffect: useEA, useCallback: useCB } = React;

function LoginScreen({ onSuccess }) {
  const [email, setEmail] = useSA('');
  const [password, setPassword] = useSA('');
  const [error, setError] = useSA('');
  const [loading, setLoading] = useSA(false);
  const inp = { width: '100%', boxSizing: 'border-box', background: '#0D1119', border: '1px solid rgba(255,255,255,0.12)', borderRadius: 12, color: '#fff', fontSize: 15, fontFamily: 'system-ui', padding: '14px 16px', outline: 'none' };
  const submit = async () => {
    if (!email || !password) return;
    setLoading(true); setError('');
    try { await window.Api.login(email, password); onSuccess(); }
    catch (e) { setError(e.message || '邮箱或密码不正确'); }
    setLoading(false);
  };
  return (
    <div style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center', background: '#05070C', padding: 24 }}>
      <div style={{ width: '100%', maxWidth: 340 }}>
        <div style={{ textAlign: 'center', marginBottom: 36 }}>
          <div style={{ fontSize: 30, fontWeight: 800, color: '#fff', letterSpacing: -1 }}>Janus</div>
          <div style={{ fontSize: 13, color: 'rgba(255,255,255,0.4)', marginTop: 5 }}>销售副驾 · 登录</div>
        </div>
        <input value={email} onChange={e => setEmail(e.target.value)} type="email" placeholder="邮箱" style={inp} />
        <input value={password} onChange={e => setPassword(e.target.value)} type="password" placeholder="密码"
          onKeyDown={e => e.key === 'Enter' && submit()}
          style={{ ...inp, marginTop: 12 }} />
        {error && <div style={{ color: '#FF6B6B', fontSize: 12, marginTop: 8, textAlign: 'center' }}>{error}</div>}
        <button onClick={submit} disabled={loading} style={{ width: '100%', marginTop: 20, padding: '14px 0', borderRadius: 14, border: 'none', background: 'linear-gradient(135deg,#6E7CFF,#A98BFF)', color: '#fff', fontSize: 15, fontWeight: 700, fontFamily: 'system-ui', cursor: loading ? 'default' : 'pointer', opacity: loading ? 0.7 : 1 }}>
          {loading ? '登录中…' : '登录'}
        </button>
      </div>
    </div>
  );
}

const TWEAK_DEFAULTS = {
  dark: true,
  accent: "#6E7CFF",
  aiLevel: "标准",
  autoplay: true,
  aiName: "老 A",
};

const TABS = [
  { id: 'home', label: '今日', icon: 'home' },
  { id: 'pipeline', label: '漏斗', icon: 'funnel' },
  { id: 'review', label: '复盘', icon: 'review' },
  { id: 'stats', label: '战绩', icon: 'chart' },
];
const IMMERSIVE = ['presence', 'warroom', 'velocity', 'company', 'person', 'gtd', 'me', 'project'];

// localStorage 持久化 hook
function useStore(key, init) {
  const [v, setV] = useSA(() => {
    try { const r = localStorage.getItem(key); return r ? JSON.parse(r) : init; } catch (e) { return init; }
  });
  useEA(() => { try { localStorage.setItem(key, JSON.stringify(v)); } catch (e) {} }, [key, v]);
  return [v, setV];
}

function App() {
  const [loggedIn, setLoggedIn] = useSA(!!(window.Api && window.Api.getToken()));
  const [t] = useSA(TWEAK_DEFAULTS);
  const T = tokens(t.dark, t.accent);
  const [stack, setStack] = useSA([{ route: 'home' }]);
  const [sheet, setSheet] = useSA(null);
  const [activeDealId, setActiveDealId] = useSA(null);

  // Listen for auth-required events (e.g., token expired)
  useEA(() => {
    const handler = () => setLoggedIn(false);
    window.addEventListener('janus:auth-required', handler);
    return () => window.removeEventListener('janus:auth-required', handler);
  }, []);

  // BANT 存储（人可覆盖 AI）
  const bantInit = {};
  CUSTOMER.bant.forEach(b => { bantInit[b.k] = { label: b.label, value: b.value, confirmed: !!b.done, by: b.done ? 'AI' : null }; });
  const [bant, setBant] = useStore('janus_bant_v2', bantInit);
  const setBantItem = (k, value) => setBant(b => ({ ...b, [k]: { ...b[k], value, confirmed: true, by: '你' } }));

  // T-1.7.2: 从 API 加载当前 deal 的 BANT（有 activeDealId 时）
  useEA(() => {
    if (!activeDealId || !window.Api?.getToken()) return;
    window.Api.request(`/api/deals/${activeDealId}/bant`)
      .then(d => {
        if (!d.bant) return;
        setBant(prev => {
          const next = { ...prev };
          ['B', 'A', 'N', 'T'].forEach(k => {
            if (d.bant[k]) next[k] = { ...prev[k], value: d.bant[k].value || prev[k].value, confirmed: !!d.bant[k].confirmed, by: d.bant[k].by || null };
          });
          return next;
        });
      })
      .catch(() => {});
  }, [activeDealId]);

  // 笔记存储
  const [notes, setNotes] = useStore('janus_notes_v3', GTD.seedNotes);
  const addNote = (note) => {
    const local = { id: Date.now(), ts: Date.now(), syncStatus: 'pending', ...note };
    setNotes(n => [local, ...n]);
    queueNoteSync(local);
  };
  const updateNote = (id, patch) => {
    const current = notes.find(x => String(x.id) === String(id));
    if (!current) return;
    const nextNote = { ...current, ...patch, ts: Date.now(), syncStatus: 'pending' };
    setNotes(n => n.map(x => String(x.id) === String(id) ? nextNote : x));
    queueNoteSync(nextNote);
  };
  const deleteNote = (id) => {
    const target = notes.find(x => String(x.id) === String(id));
    setNotes(n => n.filter(x => String(x.id) !== String(id)));
    if (window.QuickNoteApi && target) {
      window.QuickNoteApi.remove(target).catch(() => showToast('后端删除失败，本地已移除'));
    }
  };

  // 任务存储（GTD）
  const taskSeed = [
    ...GTD.today.map((x, i) => ({ id: 't' + i, section: 'today', done: false, ...x })),
    ...GTD.upcoming.map((x, i) => ({ id: 'u' + i, section: 'upcoming', done: false, ...x })),
    ...GTD.done.map((x, i) => ({ id: 'd' + i, section: 'done', done: true, ...x })),
  ];
  const [tasks, setTasks] = useStore('janus_tasks_v1', taskSeed);

  // T-1.7.1: 从 API 加载任务（有 token 时替换 seed）
  useEA(() => {
    if (!window.Api?.getToken()) return;
    window.Api.request('/api/tasks')
      .then(d => {
        if (!d.tasks?.length) return;
        const apiTasks = d.tasks.map(t => ({
          id: t.id, section: t.status === 'done' ? 'done' : 'today',
          done: t.status === 'done', text: t.title, cust: t.accountName || '', due: t.dueDate || '今天', src: 'API'
        }));
        setTasks(cur => {
          const isSeed = cur.every(c => taskSeed.some(s => s.id === c.id));
          return isSeed ? apiTasks : cur;
        });
      })
      .catch(() => {});
  }, []);
  const addTask = (task) => setTasks(ts => [{ id: 'n' + Date.now(), section: 'today', done: false, src: '手动', ...task }, ...ts]);
  const toggleTask = (id) => setTasks(ts => ts.map(x => x.id === id ? { ...x, done: !x.done } : x));
  const updateTask = (id, patch) => setTasks(ts => ts.map(x => x.id === id ? { ...x, ...patch } : x));
  const deleteTask = (id) => setTasks(ts => ts.filter(x => x.id !== id));

  // 全局 toast
  const [toast, setToast] = useSA(null);
  const showToast = useCB((msg) => { setToast(msg); clearTimeout(window.__tt); window.__tt = setTimeout(() => setToast(null), 2200); }, []);

  const queueNoteSync = useCB((localNote) => {
    if (!window.QuickNoteApi) return;
    window.QuickNoteApi.save(localNote)
      .then(synced => setNotes(current => current.map(item => String(item.id) === String(localNote.id) ? synced : item)))
      .catch(() => {
        setNotes(current => current.map(item => String(item.id) === String(localNote.id) ? { ...item, syncStatus: 'failed' } : item));
        showToast('后端同步失败，已保留本地笔记');
      });
  }, [showToast]);

  useEA(() => {
    if (!window.QuickNoteApi) return;
    window.QuickNoteApi.list()
      .then(remoteNotes => setNotes(current => mergeRemoteNotes(current, remoteNotes)))
      .catch(() => {});
  }, []);

  const top = stack[stack.length - 1];
  const scrollTop0 = () => { const sc = document.querySelector('.jn-scroll'); if (sc) sc.scrollTop = 0; };

  // 系统返回键支持：每次 go() 推一条 history，popstate 负责 pop stack
  useEA(() => {
    window.history.replaceState(null, '');
    const onPop = () => setStack(s => {
      if (s.length > 1) { setTimeout(scrollTop0, 0); return s.slice(0, -1); }
      window.history.pushState(null, ''); // 根节点：阻止退出应用
      return s;
    });
    window.addEventListener('popstate', onPop);
    return () => window.removeEventListener('popstate', onPop);
  }, []);

  const go = useCB((route, params) => {
    window.history.pushState(null, '');
    setStack(s => [...s, { route, params }]);
    setSheet(null);
    setTimeout(scrollTop0, 0);
  }, []);
  const back = useCB(() => { window.history.back(); }, []);
  const railGo = useCB((route) => {
    const ns = IMMERSIVE.includes(route) ? [{ route: 'home' }, { route }] : [{ route }];
    setStack(ns);
    window.history.replaceState(null, '');
    for (let i = 1; i < ns.length; i++) window.history.pushState(null, '');
    setSheet(null);
    setTimeout(scrollTop0, 0);
  }, []);
  const tabGo = (id) => {
    setStack([{ route: id }]);
    window.history.replaceState(null, '');
    setSheet(null);
    setTimeout(scrollTop0, 0);
  };
  const home = useCB(() => {
    setStack([{ route: 'home' }]);
    window.history.replaceState(null, '');
    setSheet(null);
    setTimeout(scrollTop0, 0);
  }, []);
  const openSheet = useCB((type, params) => setSheet({ type, params }), []);
  const closeSheet = useCB(() => setSheet(null), []);

  const logout = useCB(() => { window.Api?.logout(); }, []);
  const appApi = { go, back, railGo, home, openSheet, closeSheet, bant, setBantItem, notes, addNote, updateNote, deleteNote, tasks, addTask, toggleTask, updateTask, deleteTask, toast: showToast, aiName: t.aiName || '老 A', params: top.params || {}, activeDealId, setActiveDealId, logout };

  if (!loggedIn) return <LoginScreen onSuccess={() => setLoggedIn(true)} />;

  const screen = {
    home: <HomeScreen />,
    presence: <PresenceScreen />,
    warroom: <WarRoomScreen />,
    velocity: <VelocityScreen mode={top.params?.mode} />,
    pipeline: <PipelineScreen aiLevel={t.aiLevel} />,
    review: <ReviewScreen />,
    stats: <StatsScreen />,
    company: <CompanyScreen />,
    person: <PersonScreen name={top.params?.name} />,
    gtd: <GtdScreen />,
    me: <MeScreen />,
    project: <ProjectScreen id={top.params?.id} />,
  }[top.route];

  const isTab = !IMMERSIVE.includes(top.route);
  const noScroll = top.route === 'warroom';

  return (
    <ThemeCtx.Provider value={T}>
    <AppCtx.Provider value={appApi}>
      <div className="jn-shell" style={{ height: '100dvh', position: 'relative', display: 'flex', flexDirection: 'column', background: T.bgGrad, color: T.text, overflow: 'hidden', fontFamily: FONT }}>
        <div className="jn-scroll" style={noScroll
          ? { flex: 1, minHeight: 0, paddingTop: 52, display: 'flex', flexDirection: 'column', overflow: 'hidden' }
          : { flex: 1, minHeight: 0, overflowY: 'auto', overflowX: 'hidden', paddingTop: 52, WebkitOverflowScrolling: 'touch' }}>
          {screen}
        </div>
        {<TabBar route={top.route} tabGo={tabGo} go={go} T={T} />}

        {/* Sheet 层 */}
        {sheet && (
          <div style={{ position: 'absolute', inset: 0, zIndex: 200, display: 'flex', flexDirection: 'column', justifyContent: 'flex-end' }}>
            <div onClick={closeSheet} style={{ position: 'absolute', inset: 0, background: 'rgba(0,0,0,0.5)', backdropFilter: 'blur(2px)', animation: 'fadeIn .2s ease' }} />
            <div style={{ position: 'relative', maxHeight: '88%', display: 'flex', flexDirection: 'column', background: T.surface, borderTopLeftRadius: 24, borderTopRightRadius: 24, boxShadow: '0 -10px 40px rgba(0,0,0,0.4)', animation: 'sheetUp .3s cubic-bezier(.4,0,.2,1)', overflow: 'hidden' }}>
              <div style={{ display: 'flex', justifyContent: 'center', padding: '10px 0 4px', flexShrink: 0 }}>
                <div style={{ width: 38, height: 4, borderRadius: 2, background: T.line2 }} />
              </div>
              <div style={{ overflowY: 'auto', overflowX: 'hidden', padding: '6px 18px calc(20px + env(safe-area-inset-bottom))' }}>
                <SheetRouter type={sheet.type} params={sheet.params || {}} />
              </div>
            </div>
          </div>
        )}

        {/* 全局 toast */}
        {toast && (
          <div style={{ position: 'absolute', left: 0, right: 0, bottom: 96, display: 'flex', justifyContent: 'center', zIndex: 300, pointerEvents: 'none', padding: '0 24px' }}>
            <div style={{ background: T.dark ? 'rgba(28,34,48,0.96)' : 'rgba(20,26,38,0.94)', color: '#fff', fontSize: 13, fontWeight: 600, padding: '11px 16px', borderRadius: 12, boxShadow: '0 8px 28px rgba(0,0,0,0.4)', display: 'flex', alignItems: 'center', gap: 8, animation: 'rise .25s ease both', maxWidth: '90%' }}>
              <Icon name="check" size={15} color={T.accent} stroke={2.6} />{toast}
            </div>
          </div>
        )}
      </div>
    </AppCtx.Provider>
    </ThemeCtx.Provider>
  );
}

function mergeRemoteNotes(current, remoteNotes) {
  const hasRemote = new Set(current.map(note => note.quickNoteId).filter(Boolean));
  const hasLocal = new Set(current.map(note => String(note.id)));
  const incoming = remoteNotes.filter(note => !hasRemote.has(note.quickNoteId) && !hasLocal.has(String(note.id)));
  return [...incoming, ...current];
}

function TabBar({ route, tabGo, go, T }) {
  const left = TABS.slice(0, 2), right = TABS.slice(2);
  const item = (tab) => {
    const active = tab.id === route;
    return (
      <button key={tab.id} onClick={() => tabGo(tab.id)} style={{ flex: 1, border: 'none', background: 'transparent', cursor: 'pointer', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 4, padding: '4px 0', fontFamily: FONT }}>
        <Icon name={tab.icon} size={22} color={active ? T.accent : T.faint} stroke={active ? 2 : 1.7} />
        <span style={{ fontSize: 10.5, fontWeight: active ? 700 : 500, color: active ? T.accent : T.faint }}>{tab.label}</span>
      </button>
    );
  };
  return (
    <div style={{ flexShrink: 0, position: 'relative', display: 'flex', alignItems: 'center', padding: '8px 12px 24px', background: T.dark ? 'rgba(10,14,22,0.85)' : 'rgba(255,255,255,0.9)', backdropFilter: 'blur(20px)', WebkitBackdropFilter: 'blur(20px)', borderTop: `0.5px solid ${T.line}` }}>
      {left.map(item)}
      {/* 中央笔记入口 */}
      <div style={{ width: 64, display: 'flex', justifyContent: 'center', flexShrink: 0 }}>
        <button aria-label="行动与笔记" onClick={() => go('gtd')} style={{ position: 'relative', width: 52, height: 52, marginTop: -22, borderRadius: 18, border: 'none', cursor: 'pointer', background: `linear-gradient(135deg,${T.accent},${T.acc2})`, boxShadow: `0 6px 18px ${hexA(T.accent, 0.5)}`, display: 'flex', alignItems: 'center', justifyContent: 'center', fontFamily: FONT }}>
          <span style={{ position: 'absolute', inset: 0, borderRadius: 18, border: `2px solid ${T.accent}`, animation: 'fabPulse 2.6s ease-out infinite', pointerEvents: 'none' }} />
          <Icon name="edit" size={23} color="#fff" stroke={2.2} />
        </button>
      </div>
      {right.map(item)}
    </div>
  );
}

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