// app.jsx — 应用外壳：状态、导航、记账/许愿执行、反馈
const { useState, useRef, useCallback, useEffect } = React;

function App() {
  const [locked, setLocked] = useState(true);
  const [checking, setChecking] = useState(true); // 启动时探测会话，避免刷新后误显示锁屏
  const [screen, setScreen] = useState('home');    // home | chat | dream
  const [tx, setTx] = useState(() => loadTx());
  const [wishes, setWishes] = useState(() => loadWishes());
  const [range, setRange] = useState('week');
  const [toast, setToast] = useState(null);
  const [addOpen, setAddOpen] = useState(false);   // 记一笔底部弹层
  const [theme, setTheme] = useState(() => localStorage.getItem('coinpenguin.theme') || 'light');
  const toastTimer = useRef(null);
  const wishesRef = useRef(wishes);
  wishesRef.current = wishes;

  const balance = totalBalance(tx);

  // 启动时探测现有会话：cookie 仍有效（14 天内）则自动解锁，无需重新输密码
  useEffect(() => {
    let alive = true;
    apiHasSession().then((ok) => {
      if (!alive) return;
      if (ok) setLocked(false);
      setChecking(false);
    });
    return () => { alive = false; };
  }, []);

  // 登录后从服务端拉取最新流水与心愿，覆盖本地缓存
  useEffect(() => {
    if (locked) return;
    let alive = true;
    apiFetchTx().then((list) => { if (alive) setTx(list); }).catch(() => {});
    apiFetchWishes().then((list) => { if (alive) setWishes(list); }).catch(() => {});
    return () => { alive = false; };
  }, [locked]);

  const toggleTheme = useCallback(() => {
    setTheme((t) => {
      const n = t === 'dark' ? 'light' : 'dark';
      localStorage.setItem('coinpenguin.theme', n);
      return n;
    });
  }, []);

  const addTx = useCallback((partial) => {
    const full = { id: newId(), ts: Date.now(), note: '', ...partial };
    // 乐观更新：先本地展示并写缓存
    setTx((prev) => {
      const next = [full, ...prev];
      saveTx(next);
      return next;
    });
    // 落库到服务端；失败则保留在本地缓存，待下次同步
    apiAddTx(full).catch(() => {});
    // 浮动反馈
    setToast({ type: full.type, amount: full.amount, k: Math.random() });
    clearTimeout(toastTimer.current);
    toastTimer.current = setTimeout(() => setToast(null), 2500);
    return { ...full, balanceAfter: totalBalance([full, ...tx]) };
  }, [tx]);

  const runAction = useCallback((a) => addTx(a), [addTx]);

  // ---------- 梦想口袋：许愿 / 放飞 / 排序 ----------
  // 许愿走后端单事务（校验余额+槽位、扣 1 金币、落库），成功后把回执里的流水与心愿并入本地。
  const addWish = useCallback(async ({ title, tier, note, image }) => {
    const res = await apiAddWish({ title, tier, note, image });
    if (res && res.ok) {
      if (res.tx) setTx((prev) => { const next = [res.tx, ...prev]; saveTx(next); return next; });
      if (res.wish) setWishes((prev) => { const next = [res.wish, ...prev]; saveWishes(next); return next; });
    }
    return res || { ok: false, reason: 'error' };
  }, []);

  const updateWish = useCallback((id, patch) => {
    setWishes((prev) => {
      const next = prev.map((w) => (w.id === id ? { ...w, ...patch } : w));
      saveWishes(next);
      return next;
    });
    apiUpdateWish(id, patch).catch(() => {});
  }, []);

  const releaseWish = useCallback((id) => {
    setWishes((prev) => {
      const next = prev.filter((w) => w.id !== id);
      saveWishes(next);
      return next;
    });
    apiReleaseWish(id).catch(() => {});
  }, []);

  const reorderWishes = useCallback((orderedIds) => {
    setWishes((prev) => {
      const map = Object.fromEntries(prev.map((w) => [w.id, w]));
      const next = orderedIds.map((id) => map[id]).filter(Boolean);
      saveWishes(next);
      return next;
    });
    apiReorderWishes(orderedIds).catch(() => {});
  }, []);

  // 小企鹅在对话里执行的动作（许愿 / 放飞 / 记账）
  const aiAction = useCallback(async (a) => {
    if (a.op === 'wish_add') {
      const res = await addWish({ title: a.title || '一个心愿', tier: a.tier, note: a.note });
      return {
        kind: 'wish_add',
        ok: !!(res && res.ok),
        reason: res && res.reason,
        title: a.title || (res && res.wish && res.wish.title) || '一个心愿',
        slots: res && res.slots,
        balanceAfter: res && res.balanceAfter,
      };
    }
    if (a.op === 'wish_release') {
      const t = (a.target || '').trim();
      const w = activeWishes(wishesRef.current).find(
        (x) => x.title === t || (t && (x.title.includes(t) || t.includes(x.title)))
      );
      if (w) { releaseWish(w.id); return { kind: 'wish_release', ok: true, title: w.title }; }
      return { kind: 'wish_release', ok: false, title: t };
    }
    const r = addTx({
      type: a.type === 'income' ? 'income' : 'expense',
      cat: CATS[a.cat] ? a.cat : (a.type === 'income' ? 'allowance' : 'other'),
      amount: Math.round(a.amount),
      note: a.note || '',
    });
    return { kind: 'tx', type: r.type, amount: r.amount, cat: r.cat, note: r.note, balanceAfter: r.balanceAfter };
  }, [addWish, releaseWish, addTx]);

  const openAdd = useCallback(() => setAddOpen(true), []);

  // 会话探测中：先渲染空外框，避免短暂闪现锁屏
  if (checking) {
    return <Phone theme={theme}><div className="app-body" /></Phone>;
  }

  if (locked) {
    return (
      <Phone theme={theme}>
        <LockScreen onUnlock={() => setLocked(false)} theme={theme} onToggleTheme={toggleTheme} />
      </Phone>
    );
  }

  return (
    <Phone theme={theme}>
      <div className="app-body">
        {screen === 'home' && (
          <HomeScreen tx={tx} range={range} setRange={setRange} balance={balance}
            theme={theme} onToggleTheme={toggleTheme}
            onGoAdd={openAdd} />
        )}
        {screen === 'chat' && (
          <ChatScreen tx={tx} wishes={wishes} runAction={runAction} aiAction={aiAction} onOpenAdd={openAdd} />
        )}
        {screen === 'dream' && (
          <DreamScreen wishes={wishes} balance={balance}
            onAddWish={addWish} onReleaseWish={releaseWish} onReorder={reorderWishes}
            onUpdateWish={updateWish} onOpenAdd={openAdd} />
        )}

        {toast && (
          <div key={toast.k} className={'coin-toast ' + toast.type}>
            <Coin size={32} />{toast.type === 'income' ? '+' : '−'}{toast.amount}
          </div>
        )}
      </div>

      {/* 记一笔弹层：放在 .phone 层，覆盖整个手机（含底部导航） */}
      {addOpen && (
        <div className="add-sheet-back" onClick={() => setAddOpen(false)}>
          <div className="add-sheet" onClick={(e) => e.stopPropagation()}>
            <AddScreen onSave={addTx} onClose={() => setAddOpen(false)} />
          </div>
        </div>
      )}

      <nav className="tabbar">
        <button className={'tab' + (screen === 'home' ? ' on' : '')} onClick={() => setScreen('home')}>
          <IconHome size={24} /><span>首页</span>
        </button>
        <button className={'tab tab-peng' + (screen === 'chat' ? ' on' : '')} onClick={() => setScreen('chat')}>
          <div className="tab-peng-btn"><Penguin size={46} mood="happy" /></div>
          <span>小企鹅</span>
        </button>
        <button className={'tab' + (screen === 'dream' ? ' on' : '')} onClick={() => setScreen('dream')}>
          <IconDream size={24} /><span>梦想</span>
        </button>
      </nav>
    </Phone>
  );
}

// 手机外框
function Phone({ children, theme }) {
  return (
    <div className="phone" data-theme={theme}>
      <div className="status-bar" />
      {children}
      <div className="home-indicator" />
    </div>
  );
}

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