/* X Reply Engine + Autopilot (M19/M20). Generate/edit/batch-post replies to
   watched accounts. Autopilot is guardrailed per the addendum's autonomy flag:
   review-queue default, allowlist-only, rule-enforced, rate-limited, kill
   switch, full audit log. Posting is SIMULATED (needs X write API). */
(function () {
  const S = window.CroprStore;
  const D = window.CROPR_DATA;

  // Post a reply to X. Since Feb 2026 X blocks API replies unless the post
  // @mentions/quotes you, so: try the API (works for those cases); on the
  // restriction, fall back to opening the reply pre-filled on X for a one-click
  // manual post (only when allowIntent — the single Comment button, never bulk,
  // to avoid a swarm of popups). Offline → simulated. Rule engine enforced.
  // Returns { ok, live?, restricted?, reason? }; throws only on a real API error.
  function replyIntentUrl(tweetId, text) {
    return "https://twitter.com/intent/tweet?in_reply_to=" + encodeURIComponent(tweetId) + "&text=" + encodeURIComponent(text);
  }
  async function sendReply(r, text, allowIntent) {
    const API = window.LeapAPI;
    const org = (function () { try { const c = S.getActiveClient && S.getActiveClient(); return c && c._orgId ? c._orgId : null; } catch (e) { return null; } })();
    const live = !!(API && API.configured());
    const rc = window.CroprRules.validatePost({ content: [{ channel: "x_cropr", body: text, format: "single" }] });
    if (!rc.pass) return { ok: false, reason: "rule" };
    if (live && org && r.sourceTweetId) {
      const res = await API.social.reply(org, r.sourceTweetId, text); // {ok, restricted?, permalink?}
      if (res && res.ok) { S.markReplyPosted(r.id, res.permalink, text); return { ok: true, live: true }; }
      if (res && res.restricted) {
        if (!allowIntent) return { ok: false, reason: "restricted" };
        window.open(replyIntentUrl(r.sourceTweetId, text), "_blank", "noopener");
        S.markReplyPosted(r.id, "https://x.com/i/web/status/" + r.sourceTweetId, text);
        return { ok: true, live: true, restricted: true };
      }
      return { ok: false, reason: "api" };
    }
    S.editReply(r.id, text);
    return { ok: !!S.postReplies([r.id], "manual"), live: false };
  }

  // Draft/redraft a reply. Live: the server LLM writes it in the brand voice for
  // the chosen tone (mirrors the Composer). Offline / not configured: the local
  // template generator. Returns true when the AI wrote it.
  async function regenReply(r, tone) {
    const API = window.LeapAPI;
    const org = (function () { try { const c = S.getActiveClient && S.getActiveClient(); return c && c._orgId ? c._orgId : null; } catch (e) { return null; } })();
    const live = !!(API && API.configured());
    if (live && org) {
      const brand = (S.getBrand && S.getBrand()) || {};
      const res = await API.assistant.composeReply(org, { sourceAccount: r.sourceAccount, sourceText: r.sourceText, tone: tone, brandVoice: brand.brandVoice, brandBrief: brand.brandBrief });
      if (res && res.enabled && res.reply) { S.applyGeneratedReply(r.id, res.reply, tone); return true; }
    }
    S.generateReply(r.id, tone); // offline / fallback
    return false;
  }

  function Switch({ on, onChange, danger }) {
    return (
      <button onClick={() => onChange(!on)} aria-pressed={on} style={{ width: 46, height: 26, borderRadius: 999, border: 0, cursor: "pointer", padding: 3,
        background: on ? (danger ? "var(--danger)" : "var(--success)") : "var(--border-strong)", transition: "background 160ms", display: "flex", justifyContent: on ? "flex-end" : "flex-start" }}>
        <span style={{ width: 20, height: 20, borderRadius: 999, background: "#fff", boxShadow: "var(--shadow-sm)" }} />
      </button>
    );
  }

  function AutopilotPanel({ cfg, watch, audit, onToast }) {
    const set = (patch) => S.setAutopilot(patch);
    const autoSend = cfg.enabled && !cfg.reviewBeforeSend;
    const toggleAccount = (h) => set({ accounts: cfg.accounts.includes(h) ? cfg.accounts.filter((x) => x !== h) : [...cfg.accounts, h] });
    const toggleTone = (t) => set({ tones: cfg.tones.includes(t) ? cfg.tones.filter((x) => x !== t) : [...cfg.tones, t] });
    const runNow = () => {
      const eligible = S.getReplies().filter((r) => r.status !== "posted" && cfg.accounts.includes(r.sourceAccount)).slice(0, cfg.maxPerDay).map((r) => r.id);
      const n = S.postReplies(eligible, "autopilot");
      onToast(n ? `Autopilot sent ${n} (simulated, allowlist + rules enforced)` : "Nothing eligible to send", n ? "ok" : "error");
    };
    return (
      <Card pad={18} style={{ border: `1px solid ${autoSend ? "var(--danger)" : "var(--border)"}` }}>
        <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 4 }}>
          <Icon name="bot" size={19} color="var(--accent)" />
          <span style={{ fontSize: 14, fontWeight: 700 }}>Autopilot</span>
          <div style={{ flex: 1 }} />
          <Switch on={cfg.enabled} onChange={(v) => set({ enabled: v })} />
        </div>
        <div style={{ fontSize: 11.5, color: "var(--fg3)", marginBottom: 12 }}>Automated public replies. Default is a review queue — you approve before anything posts.</div>

        {cfg.enabled && (
          <div>
            <label style={{ display: "flex", alignItems: "center", gap: 10, padding: "8px 0", fontSize: 13 }}>
              <Switch on={!cfg.reviewBeforeSend} danger onChange={(v) => set({ reviewBeforeSend: !v })} />
              <span style={{ fontWeight: 600 }}>Auto-send (skip review)</span>
            </label>
            {autoSend && (
              <div style={{ background: "var(--danger-bg)", borderRadius: 10, padding: "9px 11px", fontSize: 11.5, color: "#8A241C", display: "flex", gap: 8, marginBottom: 10 }}>
                <Icon name="alert-triangle" size={15} color="#C6362B" /><span>Auto-send is ON — replies post automatically to allowlisted accounts. Run a queue-only shadow period first.</span>
              </div>
            )}
            <div style={{ fontSize: 11, fontWeight: 700, color: "var(--fg3)", textTransform: "uppercase", letterSpacing: ".05em", margin: "10px 0 6px" }}>Allowlist (only these)</div>
            <div style={{ display: "flex", flexWrap: "wrap", gap: 6, marginBottom: 8 }}>
              {watch.map((a) => { const on = cfg.accounts.includes(a.handle); return <button key={a.id} onClick={() => toggleAccount(a.handle)} style={{ border: `1px solid ${on ? "var(--accent)" : "var(--border-strong)"}`, background: on ? "var(--accent-weak)" : "transparent", color: on ? "var(--accent)" : "var(--fg2)", borderRadius: 999, padding: "4px 10px", fontSize: 12, fontWeight: 600, cursor: "pointer" }}>{a.handle}</button>; })}
            </div>
            <div style={{ fontSize: 11, fontWeight: 700, color: "var(--fg3)", textTransform: "uppercase", letterSpacing: ".05em", margin: "10px 0 6px" }}>Tones</div>
            <div style={{ display: "flex", flexWrap: "wrap", gap: 6, marginBottom: 10 }}>
              {D.REPLY_TONES.map((t) => { const on = cfg.tones.includes(t.id); return <button key={t.id} onClick={() => toggleTone(t.id)} style={{ border: `1px solid ${on ? "var(--accent)" : "var(--border-strong)"}`, background: on ? "var(--accent-weak)" : "transparent", color: on ? "var(--accent)" : "var(--fg2)", borderRadius: 999, padding: "4px 10px", fontSize: 12, fontWeight: 600, cursor: "pointer" }}>{t.label}</button>; })}
            </div>
            <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10, marginBottom: 10 }}>
              <label style={{ fontSize: 12, color: "var(--fg2)" }}>Max / day<input type="number" value={cfg.maxPerDay} onChange={(e) => set({ maxPerDay: +e.target.value })} style={{ width: "100%", marginTop: 4, padding: "7px 9px", borderRadius: 8, border: "1px solid var(--border-strong)", fontFamily: "inherit" }} /></label>
              <label style={{ fontSize: 12, color: "var(--fg2)" }}>Min interval (min)<input type="number" value={cfg.minIntervalMin} onChange={(e) => set({ minIntervalMin: +e.target.value })} style={{ width: "100%", marginTop: 4, padding: "7px 9px", borderRadius: 8, border: "1px solid var(--border-strong)", fontFamily: "inherit" }} /></label>
            </div>
            <div style={{ fontSize: 11, color: "var(--fg3)", display: "flex", gap: 6, alignItems: "center", marginBottom: 12 }}><Icon name="shield-check" size={14} color="var(--success)" />Rule engine enforced on every reply — non-compliant replies are never sent.</div>
            <div style={{ display: "flex", gap: 8 }}>
              {autoSend && <Button size="sm" variant="primary" icon="play" onClick={runNow}>Run now</Button>}
              <Button size="sm" variant="danger" icon="power" onClick={() => { S.killAutopilot(); onToast("Kill switch engaged — autopilot off"); }}>Kill switch</Button>
            </div>
          </div>
        )}

        {audit.length > 0 && (
          <div style={{ marginTop: 14, borderTop: "1px solid var(--border)", paddingTop: 10 }}>
            <div style={{ fontSize: 11, fontWeight: 700, color: "var(--fg3)", textTransform: "uppercase", letterSpacing: ".05em", marginBottom: 6 }}>Audit log</div>
            <div style={{ display: "flex", flexDirection: "column", gap: 6, maxHeight: 160, overflow: "auto" }}>
              {audit.slice(0, 12).map((e, i) => (
                <div key={i} style={{ fontSize: 11, color: "var(--fg2)", background: "var(--bg-subtle)", borderRadius: 8, padding: "6px 8px" }}>
                  <span style={{ fontWeight: 600 }}>{e.mode}</span> → {e.account} · {new Date(e.at).toLocaleTimeString("en-GB", { hour: "2-digit", minute: "2-digit" })}
                  <div style={{ color: "var(--fg3)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{e.reply}</div>
                </div>
              ))}
            </div>
          </div>
        )}
      </Card>
    );
  }

  function ReplyCard({ r, selected, onSelect, onToast }) {
    const [txt, setTxt] = React.useState(r.reply);
    const [regen, setRegen] = React.useState(false);
    React.useEffect(() => setTxt(r.reply), [r.reply]);
    const runRegen = async (tone) => {
      setRegen(true);
      try { const ai = await regenReply(r, tone); onToast(ai ? "Reply written with AI" : "Reply regenerated"); }
      catch (e) { onToast((e && e.message) || "Regenerate failed", "error"); }
      finally { setRegen(false); }
    };
    const rc = window.CroprRules.validatePost({ content: [{ channel: "x_cropr", body: txt, format: "single" }] });
    const posted = r.status === "posted";
    return (
      <Card pad={16} style={{ opacity: posted ? 0.6 : 1, border: `1px solid ${selected ? "var(--accent)" : "var(--border)"}` }}>
        <div style={{ display: "flex", alignItems: "flex-start", gap: 10, marginBottom: 10 }}>
          {!posted && <input type="checkbox" checked={selected} onChange={onSelect} style={{ width: 17, height: 17, marginTop: 2, accentColor: "var(--accent)" }} />}
          <div style={{ minWidth: 0, flex: 1 }}>
            <div style={{ fontSize: 12.5, fontWeight: 700 }}>{r.sourceAccount}</div>
            <div style={{ fontSize: 12.5, color: "var(--fg3)", lineHeight: 1.4, marginTop: 2 }}>{r.sourceText}</div>
            {posted && (
              <div style={{ marginTop: 8, marginLeft: 2, paddingLeft: 10, borderLeft: "2px solid var(--success)" }}>
                <div style={{ fontSize: 10.5, fontWeight: 700, color: "#0E8A50", textTransform: "uppercase", letterSpacing: ".04em", display: "flex", alignItems: "center", gap: 5 }}><Icon name="corner-down-right" size={12} color="#0E8A50" />Your reply {r.postedUrl && <a href={r.postedUrl} target="_blank" rel="noreferrer" style={{ fontWeight: 600 }}>view on X ↗</a>}</div>
                <div style={{ fontSize: 12.5, color: "var(--fg1)", lineHeight: 1.45, marginTop: 3 }}>{r.reply}</div>
              </div>
            )}
          </div>
          {posted ? <Badge color="#0E8A50" bg="var(--success-bg)" dot>Posted</Badge> : <StatusBadge status="in_draft" />}
        </div>
        {!posted && (
          <div>
            <TextArea value={txt} rows={2} onChange={(v) => { setTxt(v); }} />
            <div style={{ display: "flex", alignItems: "center", gap: 8, marginTop: 8, flexWrap: "wrap" }}>
              <Select value={r.tone} onChange={(t) => runRegen(t)} style={{ width: "auto" }} options={D.REPLY_TONES.map((t) => ({ value: t.id, label: t.label }))} />
              <Button size="sm" variant="primary" icon="message-circle" onClick={async () => {
                try {
                  const res = await sendReply(r, txt, true);
                  if (res.ok) onToast(res.restricted ? "Opened X to post your reply — click Post there" : res.live ? "Replied on X" : "Comment posted (simulated)");
                  else onToast(res.reason === "rule" ? "Fix the rule error before posting" : "Not posted", "error");
                } catch (e) { onToast((e && e.message) || "Reply failed", "error"); }
              }}>Comment</Button>
              <Button size="sm" variant="ghost" icon="save" onClick={() => { S.editReply(r.id, txt); onToast("Saved"); }}>Save</Button>
              <Button size="sm" variant="ghost" icon="refresh-cw" disabled={regen} onClick={() => runRegen(r.tone)}>{regen ? "Writing…" : "Regenerate"}</Button>
              <div style={{ flex: 1 }} />
              {!rc.pass && <span style={{ fontSize: 11, color: "#C6362B", display: "flex", gap: 4, alignItems: "center" }}><Icon name="alert-octagon" size={13} color="#C6362B" />rule error</span>}
              <span style={{ fontSize: 11, color: window.CroprRules.countChars(txt) > 280 ? "#F04438" : "var(--fg4)" }}>{window.CroprRules.countChars(txt)}/280</span>
            </div>
          </div>
        )}
      </Card>
    );
  }

  function RepliesView({ replies, autopilot, watch, audit, onToast }) {
    const [sel, setSel] = React.useState(() => new Set());
    const [filter, setFilter] = React.useState("all"); // all | replied
    const toggle = (id) => setSel((s) => { const n = new Set(s); n.has(id) ? n.delete(id) : n.add(id); return n; });
    const repliedCount = replies.filter((r) => r.status === "posted").length;
    const shown = filter === "replied" ? replies.filter((r) => r.status === "posted") : replies;
    const postSelected = async () => {
      const ids = [...sel]; let live = 0, sim = 0, restricted = 0, fail = 0;
      for (const id of ids) {
        const r = S.getReplies().find((x) => x.id === id); if (!r) continue;
        try { const res = await sendReply(r, r.reply, false); if (res.ok && res.live) live++; else if (res.ok) sim++; else if (res.reason === "restricted") restricted++; else fail++; }
        catch (e) { fail++; }
      }
      setSel(new Set());
      const posted = live + sim;
      const parts = [];
      if (posted) parts.push(`Posted ${posted}${live ? ` (${live} live on X)` : ""}`);
      if (restricted) parts.push(`${restricted} need posting on X (X blocks API replies to these)`);
      if (fail) parts.push(`${fail} failed`);
      onToast(parts.length ? parts.join(" · ") : "None posted — check rules / connection", posted || restricted ? "ok" : "error");
    };

    return (
      <div style={{ maxWidth: "var(--page-w)", margin: "0 auto", display: "grid", gridTemplateColumns: "320px minmax(0,1fr)", gap: 20, alignItems: "start" }} className="pulse-grid">
        <AutopilotPanel cfg={autopilot} watch={watch} audit={audit} onToast={onToast} />
        <div>
          <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 12, flexWrap: "wrap" }}>
            <SectionTitle icon="message-square">Reply feed · {shown.length}</SectionTitle>
            <div style={{ flex: 1 }} />
            <Segmented value={filter} onChange={setFilter} options={[{ value: "all", label: "All", icon: "list" }, { value: "replied", label: `Replied${repliedCount ? ` (${repliedCount})` : ""}`, icon: "check-check" }]} />
            {sel.size > 0 && <Button size="sm" variant="primary" icon="send" onClick={postSelected}>Post selected ({sel.size})</Button>}
          </div>
          <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
            {shown.map((r) => <ReplyCard key={r.id} r={r} selected={sel.has(r.id)} onSelect={() => toggle(r.id)} onToast={onToast} />)}
            {shown.length === 0 && <Card pad={40} style={{ textAlign: "center", color: "var(--fg3)" }}>{filter === "replied" ? "No replies posted yet." : "Add watchlist accounts in the Screener to populate replies."}</Card>}
          </div>
        </div>
      </div>
    );
  }
  window.RepliesView = RepliesView;
})();
