// Webhooks — the inbound-trigger plane mirroring the Hermes Agent dashboard's
// Webhooks page: a global enable switch + base URL, the list of subscriptions
// (each with its events, delivery target, enable toggle, and full delivery URL),
// and a create modal that turns a name + events + prompt into a new subscription.
// Wired to the dashboard config plane via /dash/api/webhooks
// (HERMES.webhooks / webhooksEnable / webhookCreate / webhookToggle / webhookDelete),
// with an offline fallback to a quiet empty preview so the standalone view renders.
const { useState, useEffect, useCallback } = React;

// deliver target -> { label, icon }. "log" writes to the agent log; "chat" routes
// the prompt into a chat session. Anything unknown falls back to a plain tag.
const DELIVER = {
  log: { label: "Log", icon: "terminal" },
  chat: { label: "Chat", icon: "chat" },
};

// Compose the full delivery URL the way the dashboard does: base_url + the
// subscription's explicit path, else /<name>. Returns "" if no base_url yet.
function deliveryUrl(base, sub) {
  if (!base) return "";
  const b = String(base).replace(/\/+$/, "");
  if (sub.url) return sub.url;
  const tail = sub.path || `/webhooks/${sub.name}`;
  return b + (tail.startsWith("/") ? tail : "/" + tail);
}

// name -> lowercase-hyphen slug (backend requires this shape for new webhooks).
function slugify(s) {
  return String(s || "").trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
}

// =====================================================================
// New-webhook modal — name (required, slugified), description, comma-separated
// events, the trigger prompt, and the delivery target. onCreate(body) does the
// HERMES.webhookCreate round-trip; the parent reloads + toasts + closes.
// =====================================================================
function NewWebhookModal({ open, busy, onCreate, onClose }) {
  const [name, setName] = useState("");
  const [description, setDescription] = useState("");
  const [events, setEvents] = useState("");
  const [prompt, setPrompt] = useState("");
  const [deliver, setDeliver] = useState("log");

  useEffect(() => {
    if (open) { setName(""); setDescription(""); setEvents(""); setPrompt(""); setDeliver("log"); }
  }, [open]);
  if (!open) return null;

  const slug = slugify(name);
  const eventList = events.split(",").map((e) => e.trim()).filter(Boolean);
  const valid = !!slug;

  const submit = () => {
    if (!valid || busy) return;
    onCreate({ name: slug, description: description.trim(), events: eventList, prompt: prompt.trim(), deliver });
  };

  return (
    <div className="modal-scrim" onMouseDown={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="modal" role="dialog" aria-modal="true">
        <div className="modal-head">
          <div className="ic"><Icon name="bolt" size={20} /></div>
          <div>
            <h2>New webhook</h2>
            <p>Turn an inbound event into an agent trigger.</p>
          </div>
          <button className="icon-btn x" onClick={onClose}><Icon name="x" size={18} /></button>
        </div>
        <div className="modal-body">
          <div className="field">
            <label>Name</label>
            <input className="input mono" autoFocus value={name} onChange={(e) => setName(e.target.value)} placeholder="github-push" />
            {name && slug !== name && <div className="faint mono" style={{ fontSize: 11.5, marginTop: 4 }}>slug: {slug || "—"}</div>}
          </div>
          <div className="field">
            <label>Description</label>
            <input className="input" value={description} onChange={(e) => setDescription(e.target.value)} placeholder="What this webhook reacts to." />
          </div>
          <div className="field">
            <label>Events</label>
            <input className="input" value={events} onChange={(e) => setEvents(e.target.value)} placeholder="push, pull_request, issues" />
            <div className="flex" style={{ gap: 6, flexWrap: "wrap", marginTop: 6 }}>
              {eventList.length
                ? eventList.map((ev, i) => <span className="tag" key={ev + i}>{ev}</span>)
                : <span className="faint mono" style={{ fontSize: 11.5 }}>comma-separated; leave blank for all events</span>}
            </div>
          </div>
          <div className="field">
            <label>Prompt</label>
            <textarea className="input" rows={4} value={prompt} onChange={(e) => setPrompt(e.target.value)}
              placeholder="What the agent should do when this fires…" style={{ resize: "vertical", lineHeight: 1.5 }} />
          </div>
          <div className="field">
            <label>Deliver to</label>
            <select className="select" value={deliver} onChange={(e) => setDeliver(e.target.value)}>
              <option value="log">Log — write to the agent log</option>
              <option value="chat">Chat — route the prompt into a session</option>
            </select>
          </div>
        </div>
        <div className="modal-foot">
          <button className="btn btn-ghost" onClick={onClose} disabled={busy}>Cancel</button>
          <button className="btn btn-primary" onClick={submit} disabled={busy || !valid}>{busy ? "Creating…" : "Create webhook"}</button>
        </div>
      </div>
    </div>
  );
}

function PageWebhooks({ toast }) {
  const [enabled, setEnabled] = useState(false);  // global webhook platform switch
  const [baseUrl, setBaseUrl] = useState("");     // base_url for delivery URLs
  const [subs, setSubs] = useState([]);           // subscriptions[]
  const [live, setLive] = useState(null);         // null=loading, true=backend, false=offline
  const [busy, setBusy] = useState(false);        // a mutation is in flight
  const [showNew, setShowNew] = useState(false);  // create modal open

  const load = useCallback(async () => {
    try {
      const w = await HERMES.webhooks();
      setEnabled(!!w.enabled);
      setBaseUrl(w.base_url || "");
      setSubs(Array.isArray(w.subscriptions) ? w.subscriptions : []);
      setLive(true);
    } catch {
      // offline fallback: quiet, empty, disabled platform.
      setEnabled(false);
      setBaseUrl("");
      setSubs([]);
      setLive(false);
    }
  }, []);

  useEffect(() => { load(); }, [load]);

  const enablePlatform = useCallback(async () => {
    setBusy(true);
    try { await HERMES.webhooksEnable(); toast("Webhooks enabled"); await load(); }
    catch (e) { toast(e.message || "Could not enable webhooks"); }
    setBusy(false);
  }, [load, toast]);

  const create = useCallback(async (body) => {
    setBusy(true);
    try {
      await HERMES.webhookCreate(body);
      toast(`Webhook “${body.name}” created`);
      setShowNew(false);
      await load();
    } catch (e) { toast(e.message || "Could not create webhook"); }
    setBusy(false);
  }, [load, toast]);

  const toggle = useCallback(async (name, next) => {
    setBusy(true);
    try { await HERMES.webhookToggle(name, next); toast(`${name} ${next ? "enabled" : "disabled"}`); await load(); }
    catch (e) { toast(e.message || "Could not update webhook"); }
    setBusy(false);
  }, [load, toast]);

  const remove = useCallback(async (name) => {
    if (!window.confirm(`Delete webhook “${name}”? This cannot be undone.`)) return;
    setBusy(true);
    try { await HERMES.webhookDelete(name); toast(`Webhook “${name}” deleted`); await load(); }
    catch (e) { toast(e.message || "Could not delete webhook"); }
    setBusy(false);
  }, [load, toast]);

  const copyUrl = useCallback(async (url) => {
    try { await navigator.clipboard.writeText(url); toast("Copied"); }
    catch { toast("Could not copy URL"); }
  }, [toast]);

  return (
    <div className="page">
      <PageHead eyebrow="Workspace" title="Webhooks" sub="Inbound triggers that hand events to Hermes Agent — globally gated, per-subscription.">
        {live === true && <span className="badge ok"><span className="d" />live</span>}
        {live === false && <span className="badge warn"><span className="d" />preview data</span>}
        {live === null && <span className="badge"><span className="d" />loading…</span>}
        <button className="btn btn-ghost" onClick={load}><Icon name="refresh" size={16} />Refresh</button>
      </PageHead>

      {/* ---- Global state + actions ---- */}
      <div className="card" style={{ marginBottom: "var(--gap)" }}>
        <div className="card-head">
          <div>
            <h2>Webhook platform</h2>
            <p>The global switch. Subscriptions only fire while the platform is enabled.</p>
          </div>
          <div className="flex" style={{ gap: 8, alignItems: "center" }}>
            {!enabled && (
              <button className="btn btn-subtle btn-sm" disabled={busy} onClick={enablePlatform}>
                <Icon name="bolt" size={14} />Enable webhooks
              </button>
            )}
            <button className="btn btn-primary btn-sm" disabled={busy} onClick={() => setShowNew(true)}>
              <Icon name="plus" size={14} />New webhook
            </button>
          </div>
        </div>
        <div className="row" style={{ cursor: "default", alignItems: "center" }}>
          <span className="glyph" style={enabled
            ? { background: "var(--success-soft)", color: "var(--success)" }
            : { background: "var(--warn-soft)", color: "var(--warn)" }}>
            <Icon name="bell" size={16} />
          </span>
          <div className="row-main">
            <div className="flex" style={{ gap: 8, alignItems: "center" }}>
              <b style={{ fontSize: 14.5 }}>Status</b>
              {enabled
                ? <span className="badge ok"><span className="d" />enabled</span>
                : <span className="badge warn"><span className="d" />disabled</span>}
            </div>
            <div className="row-sub mono">
              <span>{baseUrl ? `base: ${baseUrl}` : "no base URL reported"}</span>
            </div>
          </div>
        </div>
      </div>

      {/* ---- Subscriptions ---- */}
      <div className="card">
        <div className="card-head">
          <div>
            <h2>Subscriptions</h2>
            <p>Each subscription maps a set of events to a delivery target and prompt.</p>
          </div>
          <span className="faint mono" style={{ fontSize: 12 }}>{subs.length} subscription{subs.length === 1 ? "" : "s"}</span>
        </div>

        {!subs.length ? (
          <div className="empty">No webhooks yet. Create one with <b>New webhook</b>.</div>
        ) : (
          <div className="rows">
            {subs.map((s) => {
              const dmeta = DELIVER[s.deliver] || { label: s.deliver || "—", icon: "bolt" };
              const url = deliveryUrl(baseUrl, s);
              const evs = Array.isArray(s.events) ? s.events : [];
              return (
                <div className="row" key={s.name} style={{ cursor: "default", alignItems: "flex-start" }}>
                  <span className="glyph"><Icon name="bell" size={15} /></span>
                  <div className="row-main">
                    <div className="flex" style={{ gap: 8, alignItems: "center", flexWrap: "wrap" }}>
                      <b className="mono" style={{ fontSize: 13.5 }}>{s.name}</b>
                      <span className="tag"><Icon name={dmeta.icon} size={11} /> {dmeta.label}</span>
                      {evs.length
                        ? evs.map((ev, i) => <span className="tag" key={ev + i}>{ev}</span>)
                        : <span className="tag">all events</span>}
                    </div>
                    {s.description && <div className="row-sub" style={{ marginTop: 4 }}><span className="faint">{s.description}</span></div>}
                    {url && (
                      <div className="flex" style={{ gap: 6, alignItems: "center", marginTop: 6 }}>
                        <span className="mono faint" style={{ fontSize: 11.5, wordBreak: "break-all" }}>{url}</span>
                        <button className="icon-btn" title="Copy delivery URL" onClick={() => copyUrl(url)}>
                          <Icon name="files" size={14} />
                        </button>
                      </div>
                    )}
                  </div>
                  <div className="flex" style={{ gap: 10, alignItems: "center", alignSelf: "center" }}>
                    <Toggle on={!!s.enabled} onChange={(v) => toggle(s.name, v)} />
                    <button className="btn btn-danger btn-sm" disabled={busy} onClick={() => remove(s.name)}>
                      <Icon name="trash" size={13} />Delete
                    </button>
                  </div>
                </div>
              );
            })}
          </div>
        )}
      </div>

      <NewWebhookModal open={showNew} busy={busy} onCreate={create} onClose={() => setShowNew(false)} />
    </div>
  );
}
window.PageWebhooks = PageWebhooks;
