/* ===== Pago na Hora — Assistente "Hora" (chat IA) ===== */

const norm = s => s.normalize('NFD').replace(/[̀-ͯ]/g, '').toLowerCase();
const sumA = arr => arr.reduce((s, p) => s + (p.amount || 0), 0);

/* ---- offline fallback (only used when PNH.api is missing, e.g. a static
   preview with no backend). Reads the props handed to the component — never
   the old PNH.* mock globals — and only emits plain text/stat bubbles. ---- */
function respondOffline(text, role, ctx) {
  const t = norm(text);
  const providers = (ctx && ctx.providers) || [];
  const payments = (ctx && ctx.payments) || [];
  const receivables = (ctx && ctx.receivables) || [];

  if (role === 'pj') {
    if (/aprov|pendent|esperando|fila/.test(t)) {
      const aps = payments.filter(p => p.status === 'aprovar' || p.status === 'pendente');
      return [{ from: 'bot', type: 'text', text: aps.length
        ? 'Você tem ' + aps.length + ' pagamento(s) aguardando aprovação, somando R$ ' + PNH.fmt(sumA(aps)) + '.'
        : 'Nenhum pagamento aguardando aprovação no momento.' }];
    }
    if (/quanto.*(pag|gast)|gast|total|paguei/.test(t)) {
      const pago = payments.filter(p => p.status === 'pago');
      return [{ from: 'bot', type: 'stat', lbl: 'Total pago', val: 'R$ ' + PNH.fmt(sumA(pago)), sub: 'em ' + pago.length + ' pagamento(s)' }];
    }
    return [{ from: 'bot', type: 'text', text: 'Estou em modo offline e não consegui falar com o servidor agora. Posso te dar um resumo do que já está em tela.', quick: ['O que falta aprovar?', 'Quanto paguei?'] }];
  }

  // ---------- PF ----------
  if (/quanto.*receb|recebi|total.*receb/.test(t)) {
    const pago = receivables.filter(r => r.status === 'pago');
    return [{ from: 'bot', type: 'stat', lbl: 'Total recebido', val: 'R$ ' + PNH.fmt(sumA(pago)), sub: pago.length + ' recebimento(s)' }];
  }
  if (/pr[o ]xim.*pix|quando.*(cai|cair|receb)/.test(t)) {
    const next = receivables.find(r => r.status === 'agendado') || receivables[0];
    return [{ from: 'bot', type: 'text', text: next
      ? 'Seu próximo recebimento previsto é ' + next.from + ' (R$ ' + PNH.fmt(next.amount) + ') em ' + next.date + '.'
      : 'Não encontrei recebimentos previstos em tela.' }];
  }
  return [{ from: 'bot', type: 'text', text: 'Estou em modo offline e não consegui falar com o servidor agora. Posso te dar um resumo do que já está em tela.', quick: ['Quando cai meu próximo Pix?', 'Quanto recebi?'] }];
}

/* ---- message rendering ---- */
function AMsg({ m, onAction, onQuick }) {
  const me = m.from === 'me';
  return (
    <div className={'amsg' + (me ? ' me' : '')}>
      <div className={'aav ' + (me ? 'me' : 'bot')}>
        {me ? (m.acct || 'EU') : <Icon name="spark" size={18} color="#fff" />}
      </div>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 8, minWidth: 0 }}>
        {m.type === 'text' && <div className="abubble">{m.text}</div>}

        {m.type === 'stat' && (
          <div className="a-stat">
            <div className="lbl">{m.lbl}</div>
            <div className="val mono tnum">{m.val}</div>
            <div className="sub">{m.sub}</div>
            {m.chips && <div className="a-chips">{m.chips.map((c, i) => <span key={i}>{c}</span>)}</div>}
          </div>
        )}

        {m.type === 'cards' && (
          <div className="a-cards">
            {m.items.map((it, i) => (
              <div className="acard" key={i}>
                <Avatar name={it.name} size={34} />
                <div className="nm" style={{ fontWeight: 700, fontSize: 13.5, minWidth: 0 }}>{it.name}<small style={{ display: 'block', fontWeight: 500, color: 'var(--ink-3)', fontSize: 12 }}>{it.sub}</small></div>
                {it.amount != null
                  ? <div className="amt" style={{ fontSize: 13.5 }}>R$ {PNH.fmt(it.amount)}</div>
                  : <span className="amt"><Badge status={it.badge} /></span>}
                {it.action && <button className="btn btn-green btn-sm" style={{ padding: '6px 12px', marginLeft: 10 }} onClick={() => onAction(it.action)}>{it.action.label}</button>}
              </div>
            ))}
          </div>
        )}

        {m.type === 'action' && (
          <div className="a-action">
            <div className="row1">
              <span className="ic" style={{ width: 42, height: 42, borderRadius: 11, background: m.iconBg, display: 'grid', placeItems: 'center', flex: 'none' }}><Icon name={m.icon} size={20} color={m.iconColor} /></span>
              <div style={{ flex: 1, minWidth: 0 }}><div style={{ fontWeight: 800, fontSize: 15 }}>{m.title}</div><div className="sec mono" style={{ fontSize: 12 }}>{m.sub}</div></div>
              {m.amount != null && <div className="mono tnum" style={{ fontWeight: 800, fontSize: 18 }}>R$ {PNH.fmt(m.amount)}</div>}
            </div>
            <div className="lines">{m.lines.map((l, i) => <div key={i}>• {l}</div>)}</div>
            <div className="btns">
              {m.buttons.map((b, i) => (
                <button key={i} className={'btn btn-' + b.kind + ' btn-sm'} onClick={() => onAction(b.action)}>
                  {b.icon && <Icon name={b.icon} size={14} color={b.kind === 'green' || b.kind === 'primary' ? '#fff' : undefined} />} {b.label}
                </button>
              ))}
            </div>
          </div>
        )}

        {m.type === 'success' && (
          <div className="a-success">
            {m.text}
            {m.doc && <div className="a-doc"><Icon name="doc" size={15} color="var(--blue-600)" /> {m.doc} <Icon name="download" size={14} color="var(--ink-3)" /></div>}
          </div>
        )}

        {m.quick && <div className="aquick">{m.quick.map((q, i) => <button key={i} onClick={() => onQuick(q)}>{q}</button>)}</div>}
      </div>
    </div>
  );
}

function Assistant({ role, providers = [], payments = [], receivables = [] }) {
  const acct = role === 'pj' ? 'EN' : 'MA';
  const seed = () => ([{
    from: 'bot', type: 'text',
    text: role === 'pj'
      ? 'Oi! Sou a Hora ⚡ sua assistente da Pago na Hora. Posso aprovar Pix, te dizer quanto você gastou, cobrar contrato pendente e fechar o relatório do contador.'
      : 'Oi! Sou a Hora ⚡ sua assistente. Posso te dizer quando cai seu próximo Pix, quanto você recebeu, mandar comprovante e avisar de contrato pra assinar.',
    quick: role === 'pj'
      ? ['O que falta aprovar?', 'Quanto paguei em junho?', 'Quem não assinou contrato?']
      : ['Quando cai meu próximo Pix?', 'Quanto recebi esse mês?', 'Falta eu assinar algo?'],
  }]);

  const [msgs, setMsgs] = useState(seed);
  const [typing, setTyping] = useState(false);
  const [input, setInput] = useState('');
  const [threadId, setThreadId] = useState(null);
  const streamRef = useRef(null);

  useEffect(() => {
    const el = streamRef.current;
    if (el) el.scrollTop = el.scrollHeight;
  }, [msgs, typing]);

  const push = m => setMsgs(x => [...x, m]);

  const apiReady = () => !!(PNH.api && PNH.api.assistant && PNH.api.assistant.chat);

  // Offline fallback: replays the local prop-based engine with a typing delay.
  // Only reached when PNH.api is unavailable (e.g. static preview, no backend).
  const botReplyOffline = (replies) => {
    setTyping(true);
    setTimeout(() => {
      setTyping(false);
      replies.forEach((r, i) => setTimeout(() => push({ ...r, acct }), i * 520));
    }, 650 + Math.random() * 400);
  };

  // Sends a message through the real assistant API: shows the typing state,
  // posts {thread_id, message}, stores the returned thread_id and appends the
  // reply. On failure shows a friendly pt-BR message built from err.detail.
  const send = async (raw) => {
    const text = (raw || '').trim();
    if (!text || typing) return;
    push({ from: 'me', type: 'text', text, acct });
    setInput('');

    if (!apiReady()) {
      botReplyOffline(respondOffline(text, role, { providers, payments, receivables }));
      return;
    }

    setTyping(true);
    try {
      const res = await PNH.api.assistant.chat({ thread_id: threadId, message: text });
      if (res && res.thread_id) setThreadId(res.thread_id);
      const reply = (res && res.reply) || 'Tudo certo!';
      push({ from: 'bot', type: 'text', text: reply, acct });
    } catch (err) {
      push({ from: 'bot', type: 'text', acct, text: 'Ops, não consegui responder agora — ' + (err.detail || 'tente novamente em instantes.') });
    } finally {
      setTyping(false);
    }
  };

  // Action buttons only ever appear on offline-fallback messages. Send their
  // intent text through the same chat() path.
  const doAction = (action) => send(action.userEcho || action.label);

  const suggestions = role === 'pj'
    ? ['O que falta aprovar?', 'Paga a Marina', 'Quem não assinou contrato?', 'Gera o relatório pro contador']
    : ['Quando cai meu próximo Pix?', 'Manda meu comprovante da Lumen', 'Falta eu assinar algo?'];

  return (
    <div className="asst">
      <div className="asst-stream" ref={streamRef}>
        <div className="asst-inner">
          {msgs.map((m, i) => <AMsg key={i} m={m} onAction={doAction} onQuick={send} />)}
          {typing && (
            <div className="amsg">
              <div className="aav bot"><Icon name="spark" size={18} color="#fff" /></div>
              <div className="atyping"><i></i><i></i><i></i></div>
            </div>
          )}
        </div>
      </div>
      <div className="asst-foot">
        <div className="inner">
          <div className="asst-suggest">
            {suggestions.map((s, i) => <button key={i} onClick={() => send(s)}>{s}</button>)}
          </div>
          <div className="asst-input">
            <Icon name="spark" size={18} color="var(--violet)" />
            <input value={input} onChange={e => setInput(e.target.value)} onKeyDown={e => { if (e.key === 'Enter') send(input); }} placeholder={role === 'pj' ? 'Peça pra Hora aprovar, pagar, cobrar…' : 'Pergunte sobre seus recebimentos…'} />
            <button className="snd" disabled={!input.trim()} onClick={() => send(input)}><Icon name="send" size={18} color="#fff" /></button>
          </div>
        </div>
      </div>
    </div>
  );
}

window.Assistant = Assistant;
