// Page 4 — Rules
// Загружает правила из /api/rules. Создание/удаление/toggle идут через backend.

const RULE_YAML_TEMPLATE = `name: my_new_rule
description: |
  Короткое описание для UI.
severity: warning           # warning | critical
role: coder
claudeMdRef: agents/coder/CLAUDE.md
active: true

trigger:
  event: poll               # poll | state_changed | new_task | comment | heartbeat
  label: for-coder          # фильтр по name лейбла (опц.)
  task_state: [Todo, Backlog]   # state names (опц.)

condition:
  age_min: 5                # держится в указанных state > N минут
  dedup_hours: 1.0          # не алертить чаще раз в N часов
  respect_baseline_cutoff: true

message: "Шаблон: PB-{seq} «{title}» висит в {state} {age_min}+ минут"
`;

function RulesPage({ pushToast }) {
  const [rules, setRules] = useState(RULES);
  const [openRow, setOpenRow] = useState(null);
  const [creating, setCreating] = useState(false);

  // Перетягивает свежий список с backend (после изменений)
  const reload = async () => {
    try {
      const r = await fetch("/api/rules");
      if (r.ok) {
        const data = await r.json();
        if (Array.isArray(data)) {
          setRules(data);
          window.RULES = data;
        }
      }
    } catch (e) {
      console.warn("[rules] reload failed", e);
    }
  };

  const toggle = async (name) => {
    const rule = rules.find((r) => r.name === name);
    if (!rule) return;
    const wasActive = rule.active;
    // optimistic update
    setRules((rs) => rs.map((r) => (r.name === name ? { ...r, active: !r.active } : r)));
    try {
      const resp = await fetch(`/api/rules/${encodeURIComponent(name)}`, {
        method: "PATCH",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ active: !wasActive }),
      });
      if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
      pushToast(`Правило ${name} ${wasActive ? "приостановлено" : "включено"}`, "info");
    } catch (e) {
      // rollback
      setRules((rs) => rs.map((r) => (r.name === name ? { ...r, active: wasActive } : r)));
      pushToast(`Не удалось переключить ${name}: ${e.message}`, "crit");
    }
  };

  const remove = async (name) => {
    if (!window.confirm(`Удалить правило "${name}"?`)) return;
    try {
      const resp = await fetch(`/api/rules/${encodeURIComponent(name)}`, { method: "DELETE" });
      if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
      pushToast(`Правило ${name} удалено`, "info");
      setOpenRow(null);
      reload();
    } catch (e) {
      pushToast(`Не удалось удалить ${name}: ${e.message}`, "crit");
    }
  };

  return (
    <div className="page">
      <div className="page-header">
        <div>
          <h1 className="page-title">Правила</h1>
          <div className="page-sub">Правила watchdog'а отслеживают активность команды. Включай / приостанавливай и смотри статистику.</div>
        </div>
        <button className="btn btn-primary" onClick={() => setCreating(true)}>+ Новое правило</button>
      </div>

      <div className="card">
        <table className="tbl">
          <thead>
            <tr>
              <th style={{ width: 28 }}></th>
              <th>Имя</th>
              <th>Описание</th>
              <th style={{ width: 100 }}>Severity</th>
              <th style={{ width: 90 }}>Active</th>
              <th style={{ width: 130 }}>За 24 часа</th>
              <th style={{ width: 160 }}>Последний trigger</th>
            </tr>
          </thead>
          <tbody>
            {rules.map((r) => (
              <React.Fragment key={r.name}>
                <tr className="clickable" onClick={() => setOpenRow(openRow === r.name ? null : r.name)}>
                  <td>
                    <span style={{ color: "var(--text-muted)", fontSize: 12 }}>{openRow === r.name ? "▾" : "▸"}</span>
                  </td>
                  <td>
                    <span className="mono" style={{ fontSize: 12, fontWeight: 500, color: r.active ? "var(--text)" : "var(--text-muted)" }}>{r.name}</span>
                  </td>
                  <td style={{ color: r.active ? "var(--text-dim)" : "var(--text-muted)" }}>{r.description}</td>
                  <td><SeverityChip severity={r.severity} /></td>
                  <td onClick={(e) => e.stopPropagation()}>
                    <label className="toggle">
                      <input type="checkbox" checked={r.active} onChange={() => toggle(r.name)} />
                      <span className="track" /><span className="thumb" />
                    </label>
                    <span className="muted" style={{ fontSize: 11, marginLeft: 6 }}>{r.active ? "active" : "paused"}</span>
                  </td>
                  <td>
                    <span className="mono" style={{ fontSize: 13, color: r.triggers24h > 0 ? (r.severity === "critical" ? "var(--crit)" : r.severity === "warning" ? "var(--warn)" : "var(--info)") : "var(--text-muted)" }}>
                      {r.triggers24h}
                    </span>
                    {r.triggers24h > 0 && <span className="muted" style={{ fontSize: 11, marginLeft: 4 }}>сработ.</span>}
                  </td>
                  <td className="mono muted" style={{ fontSize: 11 }}>{r.lastTriggered ? fmtAgo(r.lastTriggered) : "—"}</td>
                </tr>
                {openRow === r.name && (
                  <tr>
                    <td colSpan={7} style={{ background: "var(--bg-elev)", padding: 0 }}>
                      <RuleDetail rule={r} onDelete={() => remove(r.name)} />
                    </td>
                  </tr>
                )}
              </React.Fragment>
            ))}
          </tbody>
        </table>
      </div>

      {creating && (
        <NewRuleDialog
          onCancel={() => setCreating(false)}
          onCreated={(name) => {
            setCreating(false);
            pushToast(`Правило ${name} создано`, "info");
            reload();
          }}
          onError={(msg) => pushToast(msg, "crit")}
        />
      )}
    </div>
  );
}

function NewRuleDialog({ onCancel, onCreated, onError }) {
  const [name, setName] = useState("my_new_rule");
  const [yamlText, setYamlText] = useState(RULE_YAML_TEMPLATE);
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState(null);

  const submit = async () => {
    setBusy(true);
    setError(null);
    try {
      const r = await fetch("/api/rules", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ name, yaml: yamlText }),
      });
      const data = await r.json().catch(() => ({}));
      if (!r.ok) {
        throw new Error(data.detail || `HTTP ${r.status}`);
      }
      onCreated(name);
    } catch (e) {
      setError(e.message);
      onError(`Не удалось создать правило: ${e.message}`);
    } finally {
      setBusy(false);
    }
  };

  return (
    <div
      role="dialog"
      aria-modal="true"
      onClick={onCancel}
      style={{
        position: "fixed",
        inset: 0,
        background: "rgba(0,0,0,0.45)",
        display: "flex",
        alignItems: "center",
        justifyContent: "center",
        zIndex: 1000,
      }}
    >
      <div
        onClick={(e) => e.stopPropagation()}
        style={{
          background: "var(--bg-elev)",
          border: "1px solid var(--border)",
          borderRadius: 8,
          padding: 20,
          width: "min(720px, 92vw)",
          maxHeight: "90vh",
          display: "flex",
          flexDirection: "column",
          gap: 14,
        }}
      >
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline" }}>
          <h2 style={{ margin: 0, fontSize: 18 }}>Новое правило</h2>
          <span className="muted" style={{ fontSize: 12 }}>
            POST /api/rules · валидация на backend через pydantic
          </span>
        </div>

        <label style={{ display: "flex", flexDirection: "column", gap: 4 }}>
          <span className="muted" style={{ fontSize: 11, textTransform: "uppercase", letterSpacing: "0.06em" }}>
            Имя (имя файла .yaml)
          </span>
          <input
            value={name}
            onChange={(e) => setName(e.target.value)}
            disabled={busy}
            className="mono"
            style={{
              padding: "6px 10px",
              fontSize: 13,
              background: "var(--bg)",
              color: "var(--text)",
              border: "1px solid var(--border)",
              borderRadius: 4,
            }}
          />
        </label>

        <label style={{ display: "flex", flexDirection: "column", gap: 4, minHeight: 0, flex: 1 }}>
          <span className="muted" style={{ fontSize: 11, textTransform: "uppercase", letterSpacing: "0.06em" }}>
            YAML
          </span>
          <textarea
            value={yamlText}
            onChange={(e) => setYamlText(e.target.value)}
            disabled={busy}
            spellCheck={false}
            className="mono"
            style={{
              padding: 10,
              fontSize: 12,
              lineHeight: 1.5,
              background: "var(--bg)",
              color: "var(--text)",
              border: "1px solid var(--border)",
              borderRadius: 4,
              resize: "vertical",
              minHeight: 320,
              width: "100%",
            }}
          />
        </label>

        {error && (
          <div style={{ color: "var(--crit)", fontSize: 12, padding: "6px 10px", background: "var(--bg)", borderRadius: 4 }}>
            {error}
          </div>
        )}

        <div style={{ display: "flex", justifyContent: "flex-end", gap: 8 }}>
          <button className="btn btn-ghost" onClick={onCancel} disabled={busy}>Отмена</button>
          <button className="btn btn-primary" onClick={submit} disabled={busy || !name || !yamlText}>
            {busy ? "Сохраняю…" : "Создать"}
          </button>
        </div>
      </div>
    </div>
  );
}

function RuleDetail({ rule, onDelete }) {
  // Mock timeline of triggers
  const timeline = useMemo(() => {
    if (rule.triggers24h === 0) return [];
    const base = new Date(rule.lastTriggered).getTime();
    const out = [];
    for (let i = 0; i < rule.triggers24h; i++) {
      out.push({
        ts: new Date(base - i * 3.6e6 * (2 + Math.random() * 3)).toISOString(),
        seq: 40 + Math.floor(Math.random() * 12),
      });
    }
    return out;
  }, [rule.name]);

  // Tasks currently matching this rule
  const applicableTasks = TASKS.filter(t => t.state === "In Progress" || t.state === "Todo").slice(0, 4);

  return (
    <div style={{ padding: 20, display: "grid", gridTemplateColumns: "1.1fr 1fr 1fr", gap: 24 }}>
      <div>
        <div className="muted" style={{ fontSize: 11, textTransform: "uppercase", letterSpacing: "0.06em", marginBottom: 6 }}>Исходник (YAML)</div>
        <YamlBlock code={rule.yaml} />
        <div style={{ marginTop: 10, fontSize: 12 }}>
          <span className="muted">Ссылается на: </span>
          <span className="mono" style={{ color: "var(--accent)" }}>{rule.claudeMdRef}</span>
        </div>
        {onDelete && (
          <div style={{ marginTop: 12 }}>
            <button
              className="btn btn-ghost"
              onClick={onDelete}
              style={{ color: "var(--crit)", fontSize: 12 }}
            >
              Удалить правило
            </button>
          </div>
        )}
      </div>

      <div>
        <div className="muted" style={{ fontSize: 11, textTransform: "uppercase", letterSpacing: "0.06em", marginBottom: 6 }}>История срабатываний</div>
        {timeline.length === 0 ? (
          <div className="muted" style={{ fontSize: 13, padding: "8px 0" }}>За 24 часа не срабатывало.</div>
        ) : (
          <div>
            {timeline.map((t, i) => (
              <div key={i} style={{ display: "grid", gridTemplateColumns: "8px 1fr auto", gap: 10, alignItems: "center", padding: "8px 0", borderBottom: "1px dashed var(--border-soft)" }}>
                <span className={`dot ${rule.severity === "critical" ? "crit" : rule.severity === "warning" ? "warn" : "ok"}`} style={{ background: rule.severity === "critical" ? "var(--crit)" : rule.severity === "warning" ? "var(--warn)" : "var(--info)" }} />
                <div>
                  <div className="mono" style={{ fontSize: 12, color: "var(--accent)" }}>PB-{t.seq}</div>
                  <div className="mono muted" style={{ fontSize: 11 }}>{fmtDateTime(t.ts)}</div>
                </div>
                <button className="btn btn-ghost" style={{ padding: "2px 6px", fontSize: 11 }}>↗</button>
              </div>
            ))}
          </div>
        )}
      </div>

      <div>
        <div className="muted" style={{ fontSize: 11, textTransform: "uppercase", letterSpacing: "0.06em", marginBottom: 6 }}>Сейчас применимо к задачам</div>
        {applicableTasks.length === 0 ? (
          <div className="muted" style={{ fontSize: 13, padding: "8px 0" }}>Ни к одной задаче.</div>
        ) : (
          <div>
            {applicableTasks.map(t => (
              <div key={t.seq} style={{ padding: "8px 0", borderBottom: "1px dashed var(--border-soft)", display: "flex", alignItems: "center", gap: 8 }}>
                <span className="mono" style={{ fontSize: 12, color: "var(--accent)", width: 56 }}>PB-{t.seq}</span>
                <span className="truncate dim" style={{ fontSize: 12, flex: 1 }}>{t.title}</span>
                <ModuleTag name={t.module} small />
              </div>
            ))}
          </div>
        )}
      </div>
    </div>
  );
}

window.RulesPage = RulesPage;
