// chat.jsx — AI 对话页：多会话历史 + 真实 LLM + 执行记账 + CLI 回执
// 会话与消息持久化在后端（SQLite），离开页面/重启后仍可查看历史。
const SUGGESTIONS = [
  '妈妈给我存了 50 金币',
  '我想要一个乐高城堡',
  '我还想要那个变形金刚吗？',
  '这周我花了多少？',
];

function buildPreamble(tx, wishes) {
  const bal = totalBalance(tx);
  const today = summarize(tx, 'today');
  const week = summarize(tx, 'week');
  const month = summarize(tx, 'month');
  const recent = [...tx].sort((a, b) => b.ts - a.ts).slice(0, 6)
    .map((t) => `${timeLabel(t.ts)} ${t.type === 'income' ? '+' : '-'}${t.amount} ${(CATS[t.cat] || {}).label} ${t.note || ''}`)
    .join('；');
  const active = activeWishes(wishes);
  const wishList = active.map((w) => `「${w.title}」(${(TIERS[w.tier] || {}).label}，已陪伴 ${wishDaysKept(w)} 天)`).join('；') || '暂无';
  return [
    '你是「金币小企鹅」，既是儿童零花钱记账管家，也是「梦想口袋」里的梦想守护者（Dream Keeper）。用户是家长或小朋友。',
    '说话要温暖、简短、活泼，像跟小朋友聊天，最多用一个表情符号。货币单位永远是「金币」。',
    '你是陪伴者和观察者，不是裁判。不说“我规定”，要说“我观察到 / 我发现”。例如不说“你必须等一个月”，而说“我发现越大的梦想通常需要多一点时间去确认”。',
    '',
    '你能真正操作这个 App。请「只」输出严格的 JSON（不要代码块标记、不要额外文字），格式：',
    '{"reply":"给用户看的一两句话","actions":[ ... ]}',
    '',
    '【记账】已经花钱买到 / 收到钱：{"op":"add","type":"income或expense","amount":数字,"cat":"分类id","note":"简短备注"}',
    '收入分类：allowance(零花钱/家长存的)、reward(奖励)。',
    '支出分类：toy(玩具)、snack(零食)、stationery(文具)、book(图书)、gift(礼物)、other(其他)。',
    '',
    '【梦想口袋】最多同时装 5 个心愿。区分两种话：',
    '· 已经拥有/买到了 → 用 add 记一笔支出。',
    '· 还没拥有、只是“想要 / 希望 / 好想要” → 用加愿：{"op":"wish_add","title":"愿望名","tier":"重量等级","note":"为什么想要"}。不要反问价格，自己猜 tier；加完在 reply 里温暖地说「已经放进梦想口袋啦」。',
    '梦想重量 tier：small(20元以内)、medium(20–200元)、large(200–1000元)、super(1000元以上)，按大概多贵猜，拿不准用 small。',
    '许一个愿会自动花掉 1 金币。若余额不足 1 金币或已有 5 个愿望，不要加愿，温柔提醒先攒金币或先放飞一个。',
    '· 让某个梦想放飞/毕业 → {"op":"wish_release","target":"愿望名"}（不说“删除”）。只有用户明确要放飞才用。',
    '· 聊愿望（“我还想要那个恐龙吗”）：用观察者语气陪伴式地聊，actions 留空 []。',
    '',
    '只聊天、问余额或统计时，actions 用空数组 []，把答案写在 reply 里。',
    '',
    '【当前账户状态】',
    `余额：${bal} 金币。`,
    `今天：收入 ${today.income}，支出 ${today.expense}。本周：收入 ${week.income}，支出 ${week.expense}。本月：收入 ${month.income}，支出 ${month.expense}。`,
    `最近记录：${recent || '暂无'}。`,
    '',
    '【梦想口袋状态】',
    `心愿槽位：${active.length} / 5。现有心愿：${wishList}。`,
  ].join('\n');
}

function parseReply(raw) {
  let txt = (raw || '').trim();
  txt = txt.replace(/```json/gi, '').replace(/```/g, '').trim();
  const a = txt.indexOf('{'); const b = txt.lastIndexOf('}');
  if (a !== -1 && b !== -1 && b > a) {
    try {
      const obj = JSON.parse(txt.slice(a, b + 1));
      return { reply: obj.reply || '', actions: Array.isArray(obj.actions) ? obj.actions : [] };
    } catch (e) {}
  }
  return { reply: txt || '我有点没听懂，可以再说一次吗？🐧', actions: [] };
}

// CLI 风格回执：记账 / 许愿 / 放飞
function Receipt({ r }) {
  if (r.kind === 'wish_add') {
    if (!r.ok) {
      const msg = r.reason === 'full' ? '梦想口袋满啦（5/5），先放飞一个吧' : '金币不够，先攒几枚金币吧';
      return (
        <div className="receipt expense">
          <code>$ dream wish ✗</code>
          <span className="receipt-tag">{msg} 🪙</span>
        </div>
      );
    }
    return (
      <div className="receipt">
        <code>$ dream wish +「{r.title}」🎈</code>
        <span className="receipt-tag">花 1 金币 · 槽位 {r.slots}/5 → 余额 {r.balanceAfter}</span>
      </div>
    );
  }
  if (r.kind === 'wish_release') {
    return (
      <div className="receipt">
        <code>$ dream release {r.ok ? '🎈' : '✗'}</code>
        <span className="receipt-tag">{r.ok ? `「${r.title}」化成气球飞走啦，和你说再见` : `没找到「${r.title}」这个梦想`}</span>
      </div>
    );
  }
  return (
    <div className={'receipt ' + r.type}>
      <code>$ {r.type === 'income' ? '存入' : '花费'} {r.type === 'income' ? '+' : '-'}{r.amount}</code>
      <span className="receipt-tag">{(CATS[r.cat] || {}).label}{r.note ? ' · ' + r.note : ''} → 余额 {r.balanceAfter}</span>
    </div>
  );
}

function ChatScreen({ tx, wishes, runAction, aiAction, onOpenAdd }) {
  const [convs, setConvs] = React.useState([]);
  const [activeId, setActiveId] = React.useState(null);
  const [msgs, setMsgs] = React.useState([]);
  const [input, setInput] = React.useState('');
  const [busy, setBusy] = React.useState(false);
  const [pending, setPending] = React.useState(null); // 待家长确认的记账/许愿操作
  const [celebrate, setCelebrate] = React.useState(null); // 许愿成功的庆祝动画（心愿名）
  const [showHistory, setShowHistory] = React.useState(false);
  const [loading, setLoading] = React.useState(true);
  const scrollRef = React.useRef(null);
  const txRef = React.useRef(tx);
  const wishRef = React.useRef(wishes);
  txRef.current = tx;
  wishRef.current = wishes;

  // 初始化：载入会话列表，选中最近一个（没有则新建）
  React.useEffect(() => {
    (async () => {
      try {
        let list = await apiListConvs();
        if (!list.length) list = [await apiCreateConv()];
        setConvs(list);
        await openConv(list[0].id);
      } catch (e) {
        setLoading(false);
      }
    })();
  }, []);

  React.useEffect(() => {
    const el = scrollRef.current;
    if (el) el.scrollTop = el.scrollHeight;
  }, [msgs, busy, pending]);

  async function refreshConvs() {
    try { setConvs(await apiListConvs()); } catch (e) {}
  }

  async function openConv(id) {
    setActiveId(id);
    setShowHistory(false);
    setPending(null); // 切换会话时丢弃未确认的操作
    setLoading(true);
    try { setMsgs(await apiGetMessages(id)); }
    catch (e) { setMsgs([]); }
    finally { setLoading(false); }
  }

  async function newConv() {
    try {
      const c = await apiCreateConv();
      setConvs((cs) => [c, ...cs]);
      await openConv(c.id);
    } catch (e) {}
  }

  async function removeConv(id, e) {
    e.stopPropagation();
    if (!window.confirm('删除这个对话？删除后不可恢复哦')) return;
    try {
      await apiDeleteConv(id);
      const rest = convs.filter((c) => c.id !== id);
      setConvs(rest);
      if (id === activeId) {
        if (rest.length) await openConv(rest[0].id);
        else await newConv();
      }
    } catch (e2) {}
  }

  const send = async (text) => {
    const userText = (text != null ? text : input).trim();
    if (!userText || busy || pending || !activeId) return;
    setInput('');
    const history = msgs.filter((m) => m.text).map((m) => ({ role: m.role, content: m.text }));
    setMsgs((m) => [...m, { id: 'u' + Date.now(), role: 'user', text: userText, acts: [] }]);
    setBusy(true);
    apiAddMessage(activeId, { role: 'user', text: userText, acts: [] }).catch(() => {});

    const llmMsgs = [
      { role: 'user', content: buildPreamble(txRef.current, wishRef.current) },
      { role: 'assistant', content: '好的，我明白啦！我会用 JSON 回复。' },
      ...history,
      { role: 'user', content: userText },
    ];

    let parsed;
    try {
      const raw = await window.claude.complete({ messages: llmMsgs });
      parsed = parseReply(raw);
    } catch (e) {
      parsed = { reply: '哎呀，我有点累了，等一下再问我好吗？🐧', actions: [] };
    }

    // 许愿 → 要花金币、占槽位，先等家长确认
    const wishAddActs = parsed.actions.filter((act) => act.op === 'wish_add');
    // 放飞 → 立即执行
    const wishRelActs = parsed.actions.filter((act) => act.op === 'wish_release');
    // 记账 → 先暂停，等家长确认（避免 LLM 识别错）
    const txActs = parsed.actions
      .filter((act) => act.op === 'add' && act.amount > 0)
      .map((act) => ({
        type: act.type === 'income' ? 'income' : 'expense',
        cat: CATS[act.cat] ? act.cat : (act.type === 'income' ? 'allowance' : 'other'),
        amount: Math.round(act.amount),
        note: act.note || '',
      }));

    const relReceipts = [];
    for (const act of wishRelActs) relReceipts.push(await aiAction(act));

    setBusy(false);

    // 许愿 → 确认卡
    if (wishAddActs.length) {
      setPending({ kind: 'wish', reply: parsed.reply, actions: wishAddActs, relReceipts });
      return;
    }
    // 记账 → 确认卡
    if (txActs.length) {
      setPending({ kind: 'tx', reply: parsed.reply, actions: txActs });
      return;
    }

    // 纯聊天 / 仅放飞 → 直接显示回复（含放飞回执）
    setMsgs((m) => [...m, { id: 'a' + Date.now(), role: 'assistant', text: parsed.reply, acts: relReceipts }]);
    apiAddMessage(activeId, { role: 'assistant', text: parsed.reply, acts: relReceipts }).catch(() => {});
    refreshConvs(); // 更新标题/预览/排序
  };

  // 家长点「确认」→ 真正执行，生成 CLI 回执
  const confirmPending = async () => {
    const p = pending;
    if (!p) return;
    setPending(null);

    if (p.kind === 'wish') {
      const receipts = [...(p.relReceipts || [])];
      let created = null;
      for (const act of p.actions) {
        const r = await aiAction(act);
        receipts.push(r);
        if (r.kind === 'wish_add' && r.ok) created = r.title;
      }
      setMsgs((m) => [...m, { id: 'a' + Date.now(), role: 'assistant', text: p.reply, acts: receipts }]);
      apiAddMessage(activeId, { role: 'assistant', text: p.reply, acts: receipts }).catch(() => {});
      refreshConvs();
      if (created) { // 成功许愿 → 庆祝动画
        setCelebrate(created);
        setTimeout(() => setCelebrate(null), 1700);
      }
      return;
    }

    // 记账
    const receipts = p.actions.map((a) => {
      const r = runAction(a);
      return { type: r.type, amount: r.amount, cat: a.cat, note: r.note, balanceAfter: r.balanceAfter };
    });
    setMsgs((m) => [...m, { id: 'a' + Date.now(), role: 'assistant', text: p.reply, acts: receipts }]);
    apiAddMessage(activeId, { role: 'assistant', text: p.reply, acts: receipts }).catch(() => {});
    refreshConvs();
  };

  // 家长点「取消」→ 丢弃操作，留一句温柔的取消提示
  const cancelPending = () => {
    if (!pending) return;
    const isWish = pending.kind === 'wish';
    setPending(null);
    const text = isWish ? '好的，这个愿先不许啦～想好了再告诉我哦 🐧' : '好的，这笔先不记啦～需要的话再告诉我哦 🐧';
    setMsgs((m) => [...m, { id: 'a' + Date.now(), role: 'assistant', text, acts: [] }]);
    apiAddMessage(activeId, { role: 'assistant', text, acts: [] }).catch(() => {});
    refreshConvs();
  };

  return (
    <div className="screen chat">
      <div className="chat-head">
        <button className="chat-icon-btn" onClick={() => setShowHistory(true)} aria-label="历史对话">
          <IconHistory size={22} />
        </button>
        <div className="chat-head-id">
          <Penguin size={40} />
          <div>
            <div className="chat-name">金币小企鹅</div>
            <div className="chat-status"><span className="dot" />在线 · 能帮你记账</div>
          </div>
        </div>
        <button className="chat-icon-btn" onClick={newConv} aria-label="新对话">
          <IconPlus size={22} />
        </button>
      </div>

      <div className="chat-scroll" ref={scrollRef}>
        {msgs.map((m) => (
          <div key={m.id} className={'msg ' + m.role}>
            {m.role === 'assistant' && <div className="msg-av"><Penguin size={34} /></div>}
            <div className="msg-col">
              {m.text && <div className="bubble">{m.text}</div>}
              {m.acts && m.acts.map((r, j) => <Receipt key={j} r={r} />)}
            </div>
          </div>
        ))}
        {busy && (
          <div className="msg assistant">
            <div className="msg-av"><Penguin size={34} /></div>
            <div className="bubble typing"><span /><span /><span /></div>
          </div>
        )}

        {pending && pending.kind === 'wish' && (
          <div className="msg assistant">
            <div className="msg-av"><Penguin size={34} /></div>
            <div className="msg-col">
              <div className="bubble">要把这个心愿放进梦想口袋吗？🌟（许一个愿要花 1 金币）</div>
              {pending.actions.map((a, j) => {
                const t = TIERS[a.tier] || TIERS.small;
                return (
                  <div key={j} className="receipt pending" style={{ borderLeftColor: t.color }}>
                    <code>$ dream wish +「{a.title || '一个心愿'}」🎈</code>
                    <span className="receipt-tag">{t.emoji} {t.label} · 花 1 金币</span>
                  </div>
                );
              })}
              <div className="confirm-row">
                <button className="confirm-btn cancel" onClick={cancelPending}>再想想</button>
                <button className="confirm-btn ok" onClick={confirmPending}>确认许愿</button>
              </div>
            </div>
          </div>
        )}

        {pending && pending.kind === 'tx' && (() => {
          let bal = totalBalance(tx); // 预测确认后的余额
          return (
            <div className="msg assistant">
              <div className="msg-av"><Penguin size={34} /></div>
              <div className="msg-col">
                <div className="bubble">我想这样记一笔，确认一下对不对呀？🐧</div>
                {pending.actions.map((a, j) => {
                  bal += a.type === 'income' ? a.amount : -a.amount;
                  return (
                    <div key={j} className={'receipt pending ' + a.type}>
                      <code>$ {a.type === 'income' ? '存入' : '花费'} {a.type === 'income' ? '+' : '-'}{a.amount}</code>
                      <span className="receipt-tag">{(CATS[a.cat] || {}).label}{a.note ? ' · ' + a.note : ''} → 余额 {bal}</span>
                    </div>
                  );
                })}
                <div className="confirm-row">
                  <button className="confirm-btn cancel" onClick={cancelPending}>取消</button>
                  <button className="confirm-btn ok" onClick={confirmPending}>确认记一笔</button>
                </div>
              </div>
            </div>
          );
        })()}
      </div>

      {celebrate && (
        <div className="wish-celebrate">
          <div className="wc-card">
            <div className="wc-emoji">🎈</div>
            <div className="wc-text">「{celebrate}」<br />放进梦想口袋啦！</div>
            <div className="wc-spark s1">✨</div>
            <div className="wc-spark s2">⭐</div>
            <div className="wc-spark s3">✨</div>
          </div>
        </div>
      )}

      {msgs.length <= 1 && !busy && !loading && (
        <div className="suggest">
          {SUGGESTIONS.map((s) => (
            <button key={s} className="suggest-chip" onClick={() => send(s)}>{s}</button>
          ))}
        </div>
      )}

      <div className="chat-input">
        <button className="chat-add" onClick={onOpenAdd} aria-label="记一笔"><IconPlus size={22} /></button>
        <input value={input} disabled={!!pending}
          placeholder={pending ? '先确认上面的操作哦…' : '和小企鹅说说话…'}
          onChange={(e) => setInput(e.target.value)}
          onKeyDown={(e) => { if (e.key === 'Enter') send(); }} />
        <button className="send-btn" onClick={() => send()} disabled={busy || !!pending || !input.trim()}>
          <IconSend size={22} />
        </button>
      </div>

      {showHistory && (
        <div className="chat-history">
          <div className="history-head">
            <span>对话记录</span>
            <button className="chat-icon-btn" onClick={() => setShowHistory(false)} aria-label="关闭">
              <IconBack size={22} />
            </button>
          </div>
          <button className="conv-new" onClick={newConv}><IconPlus size={18} /> 开始新对话</button>
          <div className="conv-list">
            {convs.map((c) => (
              <div key={c.id} className={'conv-row' + (c.id === activeId ? ' on' : '')} onClick={() => openConv(c.id)}>
                <div className="conv-main">
                  <div className="conv-title">{c.title || '新对话'}</div>
                  <div className="conv-preview">{c.preview || '还没有消息'}</div>
                </div>
                <span className="conv-time">{timeLabel(c.updated)}</span>
                <button className="conv-del" onClick={(e) => removeConv(c.id, e)} aria-label="删除">
                  <IconTrash size={18} />
                </button>
              </div>
            ))}
            {!convs.length && <div className="chat-empty">还没有对话，开始一个吧！</div>}
          </div>
        </div>
      )}
    </div>
  );
}
window.ChatScreen = ChatScreen;
