// assistant.jsx — the owner-only in-app assistant.
//
// A private chat, rendered ONLY for the platform owner, that talks to
// POST /api/assistant. It can read the whole book and PREPARE corrections; every
// write is shown as a proposal the owner must Confirm, which POSTs to
// /api/assistant/apply. Nothing here can mutate data on its own — the confirm
// step is the gate, and the server re-validates + re-checks owner on apply.
//
// Conversation state lives here in the client; each turn we send the plain
// text history and the server re-reads the book fresh via its tools.

const _asstUid = (() => { let n = 0; return () => "m" + (++n) + "_" + Math.random().toString(36).slice(2, 6); })();

// One prepared change (override / delete) with a Confirm / Cancel affordance.
function AssistantProposal({ proposal, onConfirm, onCancel }) {
  const p = proposal;
  const status = p._status; // undefined | 'applying' | 'applied' | 'failed' | 'cancelled'
  const fmt = (v) => v === null || v === undefined ? "—" : String(v);

  return (
    <div className={"asst-prop" + (status ? " is-" + status : "")}>
      <div className="asst-prop-head">
        <span className="asst-prop-kind">{p.type === "delete" ? "Delete" : "Fix"}</span>
        <span className="asst-prop-label">{p.label || (p.type === "delete" ? (p.event_ids || []).length + " event(s)" : p.event_id)}</span>
      </div>
      {p.reason && <div className="asst-prop-reason">{p.reason}</div>}

      {p.type === "override" && (
        <div className="asst-prop-diff">
          {Object.keys(p.patch || {}).map((k) => (
            <div className="asst-diff-row" key={k}>
              <span className="asst-diff-k">{k}</span>
              <span className="asst-diff-before">{fmt((p.before || {})[k])}</span>
              <span className="asst-diff-arrow">→</span>
              <span className="asst-diff-after">{fmt(p.patch[k])}</span>
            </div>
          ))}
        </div>
      )}
      {p.type === "delete" && (
        <div className="asst-prop-diff">
          {(p.preview || []).map((e) => (
            <div className="asst-diff-row" key={e.id}>
              <span className="asst-diff-k">{e.t}</span>
              <span className="asst-diff-before">{String(e.action || "").toUpperCase()} {e.ticker}</span>
              <span className="asst-diff-after">{fmt(e.price)}</span>
            </div>
          ))}
        </div>
      )}

      {!status && (
        <div className="asst-prop-actions">
          <button className="btn primary sm" onClick={onConfirm}>Confirm</button>
          <button className="btn ghost sm" onClick={onCancel}>Cancel</button>
        </div>
      )}
      {status === "applying" && <div className="asst-prop-note">Applying…</div>}
      {status === "applied" && <div className="asst-prop-note ok">✓ Applied — the view refreshes in a few seconds.</div>}
      {status === "cancelled" && <div className="asst-prop-note">Cancelled.</div>}
      {status === "failed" && <div className="asst-prop-note bad">Couldn't apply{p._err ? " — " + p._err : ""}.</div>}
    </div>
  );
}

const ASSISTANT_HINTS = [
  "Why is INSTINCT LRCX showing that P&L?",
  "Find positions with no cost basis",
  "Which of DEV's trades closed red this week?",
];

function AssistantWidget({ isOwner, onApplied }) {
  const [open, setOpen] = useState(false);
  const [messages, setMessages] = useState([]);
  const [input, setInput] = useState("");
  const [sending, setSending] = useState(false);
  const scrollRef = useRef(null);

  useEffect(() => {
    if (scrollRef.current) scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
  }, [messages, open, sending]);

  if (!isOwner) return null;

  async function send(text) {
    const q = (text != null ? text : input).trim();
    if (!q || sending) return;
    const next = [...messages, { id: _asstUid(), role: "user", text: q }];
    setMessages(next);
    setInput("");
    setSending(true);
    try {
      const apiMsgs = next
        .map((m) => ({ role: m.role === "bot" ? "assistant" : "user", content: m.text }))
        .filter((m) => m.content);
      const r = await tapeSend(apiBase() + "/api/assistant", {
        method: "POST", headers: { "content-type": "application/json" },
        body: JSON.stringify({ messages: apiMsgs }),
      });
      const j = await r.json();
      setMessages((m) => [...m, { id: _asstUid(), role: "bot", text: j.reply || "", proposals: (j.proposals || []) }]);
    } catch (e) {
      setMessages((m) => [...m, { id: _asstUid(), role: "bot", text: "⚠️ " + (e.message || "something went wrong") }]);
    } finally {
      setSending(false);
    }
  }

  async function confirm(msgId, proposal) {
    const mark = (patch) => setMessages((m) => m.map((x) =>
      x.id === msgId ? { ...x, proposals: x.proposals.map((p) => p === proposal ? { ...p, ...patch } : p) } : x));
    mark({ _status: "applying" });
    try {
      const r = await tapeSend(apiBase() + "/api/assistant/apply", {
        method: "POST", headers: { "content-type": "application/json" },
        body: JSON.stringify({ proposals: [proposal] }),
      });
      const j = await r.json();
      const res = j.results && j.results[0];
      if (res && res.ok) { mark({ _status: "applied" }); if (onApplied) onApplied(j); }
      else mark({ _status: "failed", _err: (res && res.error) || "unknown error" });
    } catch (e) {
      mark({ _status: "failed", _err: e.message });
    }
  }

  function cancel(msgId, proposal) {
    setMessages((m) => m.map((x) =>
      x.id === msgId ? { ...x, proposals: x.proposals.map((p) => p === proposal ? { ...p, _status: "cancelled" } : p) } : x));
  }

  return (
    <>
      <button
        className={"asst-fab" + (open ? " open" : "")}
        onClick={() => setOpen((o) => !o)}
        aria-label={open ? "Close assistant" : "Open assistant"}
        title="Assistant"
      >
        {open ? "✕" : (
          <svg viewBox="0 0 24 24" width="20" height="20" aria-hidden="true">
            <path fill="currentColor" d="M12 2.5l1.7 4.4 4.4 1.7-4.4 1.7L12 14.7l-1.7-4.4L5.9 8.6l4.4-1.7L12 2.5zM18.5 14l.9 2.3 2.3.9-2.3.9-.9 2.3-.9-2.3-2.3-.9 2.3-.9.9-2.3z" />
          </svg>
        )}
      </button>

      {open && (
        <div className="asst-panel" role="dialog" aria-label="Assistant">
          <div className="asst-head">
            <div className="asst-title"><span className="asst-dot" /> Assistant</div>
            <button className="asst-close" onClick={() => setOpen(false)} aria-label="Close">✕</button>
          </div>

          <div className="asst-msgs" ref={scrollRef}>
            {messages.length === 0 && (
              <div className="asst-empty">
                <p>Ask about your book, or tell me what to fix — I'll show the change for you to confirm before anything is written.</p>
                <div className="asst-hints">
                  {ASSISTANT_HINTS.map((h) => (
                    <button key={h} className="asst-hint" onClick={() => send(h)}>{h}</button>
                  ))}
                </div>
              </div>
            )}
            {messages.map((m) => (
              <div key={m.id} className={"asst-msg " + m.role}>
                {m.text && <div className="asst-bubble">{m.text}</div>}
                {(m.proposals || []).map((p, i) => (
                  <AssistantProposal key={i} proposal={p}
                    onConfirm={() => confirm(m.id, p)} onCancel={() => cancel(m.id, p)} />
                ))}
              </div>
            ))}
            {sending && <div className="asst-msg bot"><div className="asst-bubble asst-typing"><span /><span /><span /></div></div>}
          </div>

          <div className="asst-input-row">
            <textarea
              className="asst-input"
              rows={1}
              placeholder="Ask or instruct…"
              value={input}
              onChange={(e) => setInput(e.target.value)}
              onKeyDown={(e) => { if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); send(); } }}
            />
            <button className="asst-send" onClick={() => send()} disabled={sending || !input.trim()} aria-label="Send">↑</button>
          </div>
        </div>
      )}
    </>
  );
}

Object.assign(window, { AssistantWidget, AssistantProposal });
