// Reminder + routing settings.
//
//   etaMinutes        — the promise: how soon the customer gets their first update.
//                       Also what the SLA cron measures a breach against.
//   remindEveryMinutes— once breached, how often Slack re-nags about that ticket.
//   routing           — where an approved ticket lands by default (admin can
//                       always override per ticket at approval time).
//
// Per-client overrides beat the global row for the severities they name — that's
// how a VIP account gets a 1-hour SEV3 promise while everyone else gets 8.
const { useState: useStateRS, useEffect: useEffectRS } = React;

const RS_SEVS = ["SEV1", "SEV2", "SEV3", "SEV4"];

// Minutes <-> a human string, so nobody types "2880".
function fmtMin(m) {
  if (!m && m !== 0) return "";
  if (m < 60) return m + "m";
  if (m % 1440 === 0) return (m / 1440) + "d";
  if (m % 60 === 0) return (m / 60) + "h";
  return m + "m";
}
function parseMin(s) {
  const m = String(s).trim().match(/^(\d+(?:\.\d+)?)\s*([mhd])?$/i);
  if (!m) return NaN;
  const n = parseFloat(m[1]);
  const unit = (m[2] || "m").toLowerCase();
  return Math.round(n * (unit === "d" ? 1440 : unit === "h" ? 60 : 1));
}

function MinField({ value, onChange, disabled }) {
  const [text, setText] = useStateRS(fmtMin(value));
  useEffectRS(() => { setText(fmtMin(value)); }, [value]);
  const bad = text !== "" && !isFinite(parseMin(text));
  return (
    <input className={"rs-min" + (bad ? " is-bad" : "")} value={text} disabled={disabled}
      placeholder="e.g. 2h"
      onChange={(e) => setText(e.target.value)}
      onBlur={() => { const n = parseMin(text); if (isFinite(n) && n >= 1) onChange(n); else setText(fmtMin(value)); }} />
  );
}

function SevRows({ table, base, onSet, onClear, disabled }) {
  return (
    <table className="rs-table">
      <thead>
        <tr><th>Severity</th><th>First update due</th><th>Re-nag every</th><th /></tr>
      </thead>
      <tbody>
        {RS_SEVS.map((s) => {
          const eff = Object.assign({}, base[s], table[s]);
          // Only the per-client table can "override" — in the defaults table
          // `table` IS `base`, so every row would otherwise look overridden.
          const over = !!onClear && !!table[s];
          return (
            <tr key={s} className={over ? "is-over" : ""}>
              <td><span className={"sev-chip sev-" + window.NS.sev(s).rank}><span className="sev-dot" />{s}</span></td>
              <td><MinField value={eff.etaMinutes} disabled={disabled} onChange={(v) => onSet(s, "etaMinutes", v)} /></td>
              <td><MinField value={eff.remindEveryMinutes} disabled={disabled} onChange={(v) => onSet(s, "remindEveryMinutes", v)} /></td>
              <td>{over && onClear
                ? <button className="btn btn-ghost btn-sm" disabled={disabled} onClick={() => onClear(s)}>Reset</button>
                : <span className="rs-dim">{onClear ? "inherits" : ""}</span>}</td>
            </tr>
          );
        })}
      </tbody>
    </table>
  );
}

function ReminderSettings() {
  const [live, setLive] = useStateRS(false);
  const [settings, setSettings] = useStateRS(null);
  const [dirty, setDirty] = useStateRS(false);
  const [busy, setBusy] = useStateRS(false);
  const [msg, setMsg] = useStateRS("");
  const [acct, setAcct] = useStateRS("");
  const [newAcct, setNewAcct] = useStateRS("");

  useEffectRS(() => {
    window.NS.admin.getSettings().then((r) => { setLive(!!r.live); setSettings(r.settings); });
  }, []);

  if (!settings) return <div className="pq-empty">Loading settings…</div>;

  const base = settings.reminders;
  const accounts = Object.keys(settings.accounts || {});

  function mutate(fn) {
    const next = JSON.parse(JSON.stringify(settings));
    fn(next);
    setSettings(next); setDirty(true); setMsg("");
  }
  const setGlobal = (s, k, v) => mutate((n) => { (n.reminders[s] = n.reminders[s] || {})[k] = v; });
  const setAcctVal = (s, k, v) => mutate((n) => {
    n.accounts[acct] = n.accounts[acct] || {};
    (n.accounts[acct][s] = n.accounts[acct][s] || {})[k] = v;
  });
  const clearAcctSev = (s) => mutate((n) => { if (n.accounts[acct]) delete n.accounts[acct][s]; });
  const setRoute = (s, v) => mutate((n) => { n.routing[s] = v; });

  function addAccount() {
    const slug = String(newAcct).toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
    if (!slug) return;
    mutate((n) => { n.accounts[slug] = n.accounts[slug] || {}; });
    setAcct(slug); setNewAcct("");
  }
  function removeAccount() {
    if (!acct) return;
    mutate((n) => { delete n.accounts[acct]; });
    setAcct("");
  }

  async function save() {
    setBusy(true); setMsg("");
    const res = await window.NS.admin.putSettings({
      reminders: settings.reminders, accounts: settings.accounts, routing: settings.routing,
    });
    setBusy(false);
    if (res && res.ok) { setSettings(res.settings); setDirty(false); setMsg("Saved."); if (window.fireToast) window.fireToast("Reminder settings saved"); }
    else setMsg(res && res.error === "no_store" ? "No datastore configured — settings can't persist." : `Couldn't save: ${(res && res.error) || "unknown"}`);
  }

  return (
    <div>
      <div className="page-head">
        <div className="eyebrow">Settings</div>
        <h1 className="page-title">Reminders &amp; routing</h1>
        <p className="page-sub">
          How long we promise a first update, how often Slack re-nags once that promise is broken, and where an
          approved ticket lands. Accept <code>30m</code>, <code>2h</code>, <code>2d</code>.
        </p>
      </div>

      {!live && (
        <div className="admin-note">
          <strong>Not persisted.</strong> No datastore is configured, so these are the built-in defaults and edits
          won't stick. Set <code>UPSTASH_REDIS_REST_URL</code> + <code>UPSTASH_REDIS_REST_TOKEN</code>.
        </div>
      )}

      <section className="card rs-card">
        <h2 className="rs-h">Defaults — every account</h2>
        <SevRows table={base} base={base} onSet={setGlobal} disabled={busy} />
      </section>

      <section className="card rs-card">
        <h2 className="rs-h">Per-client overrides</h2>
        <p className="rs-sub">Only the severities you set here differ; the rest inherit the defaults above.</p>
        <div className="rs-acct">
          <select className="fsel" value={acct} onChange={(e) => setAcct(e.target.value)}>
            <option value="">Choose a client…</option>
            {accounts.map((a) => <option key={a} value={a}>{a}</option>)}
          </select>
          <input className="fsearch rs-new" placeholder="add a client (e.g. acme-corp)"
            value={newAcct} onChange={(e) => setNewAcct(e.target.value)}
            onKeyDown={(e) => { if (e.key === "Enter") addAccount(); }} />
          <button className="btn btn-ghost btn-sm" onClick={addAccount} disabled={!newAcct.trim()}>Add</button>
          {acct && <button className="btn btn-ghost btn-sm" onClick={removeAccount}>Remove {acct}</button>}
        </div>
        {acct
          ? <SevRows table={(settings.accounts[acct]) || {}} base={base} onSet={setAcctVal} onClear={clearAcctSev} disabled={busy} />
          : <div className="rs-dim rs-none">Pick or add a client to give it its own clock.</div>}
      </section>

      <section className="card rs-card">
        <h2 className="rs-h">Approval routing</h2>
        <p className="rs-sub">Where an approved ticket goes by default. An admin can always override at approval time.</p>
        <table className="rs-table">
          <tbody>
            {RS_SEVS.map((s) => (
              <tr key={s}>
                <td><span className={"sev-chip sev-" + window.NS.sev(s).rank}><span className="sev-dot" />{s}</span></td>
                <td>
                  <div className="seg">
                    {["sprint", "backlog"].map((d) => (
                      <button key={d} type="button" className={settings.routing[s] === d ? "is-active" : ""}
                        onClick={() => setRoute(s, d)} disabled={busy}>
                        {d === "sprint" ? "Current sprint" : "Backlog"}
                      </button>
                    ))}
                  </div>
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      </section>

      <div className="rs-save">
        <button className="btn btn-primary" onClick={save} disabled={!dirty || busy || !live}>
          {busy ? "Saving…" : "Save settings"}
        </button>
        {msg && <span className="rs-msg">{msg}</span>}
        {dirty && !busy && <span className="rs-dim">Unsaved changes</span>}
      </div>
    </div>
  );
}

window.ReminderSettings = ReminderSettings;
