/* eslint-disable */
// LlmConfigPanel — editable model routing rules
// Props (TS): { rules?: Rule[]; providers?: string[] }
// Rule = { id; task; primary; fallback; maxLatencyMs; priority; enabled }

const MODELS = [
  { id: "deepseek/chat",      name: "DeepSeek Chat",        provider: "DeepSeek",   tone: "good" },
  { id: "deepseek/coder",     name: "DeepSeek Coder",       provider: "DeepSeek",   tone: "good" },
  { id: "moonshot/k2-32k",    name: "Moonshot K2-32k",      provider: "Moonshot",   tone: "good" },
  { id: "moonshot/k2-128k",   name: "Moonshot K2-128k",     provider: "Moonshot",   tone: "good" },
  { id: "xai/grok-4",         name: "Grok 4",               provider: "xAI",        tone: "warn" },
  { id: "xai/grok-mini",      name: "Grok Mini",            provider: "xAI",        tone: "warn" },
  { id: "openrouter/auto",    name: "OpenRouter Auto",      provider: "OpenRouter", tone: "info" },
  { id: "openrouter/sonnet",  name: "OpenRouter · Sonnet",  provider: "OpenRouter", tone: "info" },
];

const INITIAL_RULES = [
  { id: "r1", task: "chat.default",         primary: "deepseek/chat",     fallback: "openrouter/auto",   maxLatencyMs: 1500, priority: 1, enabled: true },
  { id: "r2", task: "summarise.long",       primary: "moonshot/k2-128k",  fallback: "openrouter/sonnet", maxLatencyMs: 4000, priority: 2, enabled: true },
  { id: "r3", task: "news.interpret",       primary: "xai/grok-4",        fallback: "deepseek/chat",     maxLatencyMs: 2500, priority: 3, enabled: true },
  { id: "r4", task: "code.refactor",        primary: "deepseek/coder",    fallback: "openrouter/sonnet", maxLatencyMs: 3000, priority: 2, enabled: true },
  { id: "r5", task: "tool_call.structured", primary: "deepseek/chat",     fallback: "moonshot/k2-32k",   maxLatencyMs: 1200, priority: 1, enabled: true },
  { id: "r6", task: "monitoring.summary",   primary: "moonshot/k2-32k",   fallback: "deepseek/chat",     maxLatencyMs: 2000, priority: 4, enabled: false },
];

function LlmConfigPanel() {
  const [rules, setRules] = useState(INITIAL_RULES);
  const [edit, setEdit] = useState(null); // {ruleId, field}
  const [dragId, setDragId] = useState(null);
  const [dropIdx, setDropIdx] = useState(null);
  const [dirty, setDirty] = useState(false);

  const updateRule = (id, patch) => {
    setRules((rs) => rs.map((r) => r.id === id ? { ...r, ...patch } : r));
    setDirty(true);
  };
  const deleteRule = (id) => {
    setRules((rs) => rs.filter((r) => r.id !== id));
    setDirty(true);
  };
  const addRule = () => {
    setRules((rs) => [...rs, {
      id: "r" + (Date.now()).toString(36),
      task: "new.task",
      primary: "deepseek/chat",
      fallback: "openrouter/auto",
      maxLatencyMs: 2000,
      priority: rs.length + 1,
      enabled: true,
    }]);
    setDirty(true);
  };

  return (
    <div style={{ padding: 24, display: "flex", flexDirection: "column", gap: 16, minHeight: 0 }}>
      <header style={{ display: "flex", alignItems: "center", gap: 12 }}>
        <div style={{ flex: 1, minWidth: 0 }}>
          <h2 style={{ margin: 0, fontSize: 20, fontWeight: 700, letterSpacing: "-0.015em" }}>
            LLM Routing Rules
          </h2>
          <p style={{ margin: "2px 0 0", fontSize: 13, color: "var(--text-3)" }}>
            Pi consults these top-to-bottom. First match wins; fallback fires if primary breaches the latency budget or returns an error.
          </p>
        </div>
        <Pill tone={dirty ? "warn" : "good"} soft>
          {dirty
            ? <><StatusDot tone="warn" size={6}/> Unsaved changes</>
            : <><I.Check size={11}/> In sync</>}
        </Pill>
        <Btn kind="ghost" size="sm" icon={<I.Plus size={13}/>} onClick={addRule}>Add rule</Btn>
        <Btn kind="primary" size="md" icon={<I.Save size={13}/>}
          disabled={!dirty} onClick={() => setDirty(false)}>Save changes</Btn>
      </header>

      {/* table-ish thing — built with divs so each row is a flex container */}
      <div style={{
        background: "var(--bg-1)",
        border: "1px solid var(--border-s)",
        borderRadius: "var(--r-lg)",
        overflow: "hidden",
      }}>
        {/* header row */}
        <div style={{
          display: "grid",
          gridTemplateColumns: "28px 1.4fr 1.4fr 1.4fr 0.9fr 0.7fr 0.6fr 36px",
          gap: 12,
          padding: "12px 16px",
          background: "oklch(0.185 0.022 250)",
          borderBottom: "1px solid var(--border-s)",
          alignItems: "center",
        }}>
          <span/>
          <Th>Task</Th>
          <Th>Primary model</Th>
          <Th>Fallback model</Th>
          <Th align="right">Max latency</Th>
          <Th align="right">Priority</Th>
          <Th align="center">Enabled</Th>
          <span/>
        </div>

        {rules.map((r, i) => (
          <RuleRow key={r.id} r={r} index={i}
            dropAbove={dropIdx === i && dragId !== r.id}
            dragging={dragId === r.id}
            edit={edit}
            setEdit={setEdit}
            update={updateRule}
            del={deleteRule}
            onDragStart={() => setDragId(r.id)}
            onDragOver={(e) => { e.preventDefault(); setDropIdx(i); }}
            onDragEnd={() => {
              if (dragId && dropIdx !== null) {
                const from = rules.findIndex((x) => x.id === dragId);
                if (from !== -1 && from !== dropIdx) {
                  const next = rules.slice();
                  const [moved] = next.splice(from, 1);
                  next.splice(dropIdx > from ? dropIdx - 1 : dropIdx, 0, moved);
                  setRules(next);
                  setDirty(true);
                }
              }
              setDragId(null); setDropIdx(null);
            }}
          />
        ))}

        {/* footer */}
        <div style={{
          padding: "10px 16px",
          borderTop: "1px solid var(--border-s)",
          background: "oklch(0.185 0.022 250)",
          fontSize: 11.5, color: "var(--text-3)",
          display: "flex", alignItems: "center", gap: 14,
        }} className="mono">
          {rules.length} rules · {rules.filter(r=>r.enabled).length} active · drag <I.Drag size={11} style={{ verticalAlign: "-2px" }}/> to reorder
        </div>
      </div>

      {/* live preview of the routing decision */}
      <RoutingPreview rules={rules}/>
    </div>
  );
}

function Th({ children, align = "left" }) {
  return (
    <span className="mono" style={{
      fontSize: 10.5, letterSpacing: "0.12em",
      textTransform: "uppercase",
      color: "var(--text-4)",
      fontWeight: 600,
      textAlign: align,
    }}>{children}</span>
  );
}

function RuleRow({ r, index, dropAbove, dragging, edit, setEdit, update, del, onDragStart, onDragOver, onDragEnd }) {
  const model = (id) => MODELS.find((m) => m.id === id);
  const primary = model(r.primary);
  const fallback = model(r.fallback);

  return (
    <div
      draggable
      onDragStart={onDragStart} onDragOver={onDragOver} onDragEnd={onDragEnd}
      style={{
        position: "relative",
        display: "grid",
        gridTemplateColumns: "28px 1.4fr 1.4fr 1.4fr 0.9fr 0.7fr 0.6fr 36px",
        gap: 12,
        padding: "12px 16px",
        alignItems: "center",
        borderTop: dropAbove ? "2px solid var(--accent)" : "1px solid var(--border-s)",
        opacity: dragging ? 0.4 : (r.enabled ? 1 : 0.55),
        background: dragging ? "var(--bg-2)" : "transparent",
        transition: "background 120ms ease",
      }}
      onMouseEnter={(e) => { if (!dragging) e.currentTarget.style.background = "oklch(0.215 0.025 248)"; }}
      onMouseLeave={(e) => { if (!dragging) e.currentTarget.style.background = "transparent"; }}
    >
      {/* drag handle */}
      <span style={{ color: "var(--text-4)", cursor: "grab", display: "inline-flex" }}>
        <I.Drag size={14}/>
      </span>

      {/* task — editable text */}
      <EditableText
        value={r.task}
        editing={edit?.ruleId === r.id && edit?.field === "task"}
        onStart={() => setEdit({ ruleId: r.id, field: "task" })}
        onCommit={(v) => { update(r.id, { task: v }); setEdit(null); }}
        onCancel={() => setEdit(null)}
        mono
      />

      {/* primary model dropdown */}
      <ModelSelect value={r.primary} onChange={(v) => update(r.id, { primary: v })} model={primary}/>

      {/* fallback model dropdown */}
      <ModelSelect value={r.fallback} onChange={(v) => update(r.id, { fallback: v })} model={fallback} muted/>

      {/* max latency — editable number */}
      <EditableText
        value={r.maxLatencyMs}
        suffix=" ms"
        align="right"
        editing={edit?.ruleId === r.id && edit?.field === "latency"}
        onStart={() => setEdit({ ruleId: r.id, field: "latency" })}
        onCommit={(v) => { update(r.id, { maxLatencyMs: parseInt(v, 10) || 0 }); setEdit(null); }}
        onCancel={() => setEdit(null)}
        mono
      />

      {/* priority — chip stepper */}
      <div style={{ display: "flex", justifyContent: "flex-end" }}>
        <PriorityChip value={r.priority} onChange={(v) => update(r.id, { priority: v })}/>
      </div>

      {/* enabled toggle */}
      <div style={{ display: "flex", justifyContent: "center" }}>
        <Toggle2 on={r.enabled} onChange={(v) => update(r.id, { enabled: v })}/>
      </div>

      {/* row actions */}
      <IconButton title="Delete rule" onClick={() => del(r.id)}>
        <I.Trash size={13}/>
      </IconButton>
    </div>
  );
}

function EditableText({ value, suffix = "", align = "left", editing, onStart, onCommit, onCancel, mono }) {
  const [draft, setDraft] = useState(String(value));
  useEffect(() => { if (editing) setDraft(String(value)); }, [editing, value]);
  if (editing) {
    return (
      <input
        autoFocus
        value={draft}
        onChange={(e) => setDraft(e.target.value)}
        onBlur={() => onCommit(draft)}
        onKeyDown={(e) => {
          if (e.key === "Enter") onCommit(draft);
          if (e.key === "Escape") onCancel();
        }}
        className={mono ? "mono" : ""}
        style={{
          width: "100%",
          padding: "4px 8px",
          background: "var(--bg-0)",
          border: "1px solid var(--accent-dim)",
          borderRadius: "var(--r-sm)",
          color: "var(--text-1)",
          fontSize: 13,
          outline: "none",
          textAlign: align,
        }}
      />
    );
  }
  return (
    <button
      onClick={onStart}
      className={mono ? "mono" : ""}
      style={{
        background: "transparent",
        color: "var(--text-1)",
        border: "1px solid transparent",
        borderRadius: "var(--r-sm)",
        padding: "4px 8px",
        fontSize: 13,
        textAlign: align,
        cursor: "text",
        transition: "all 120ms ease",
        width: "100%",
      }}
      onMouseEnter={(e) => { e.currentTarget.style.background = "var(--bg-2)"; e.currentTarget.style.borderColor = "var(--border-s)"; }}
      onMouseLeave={(e) => { e.currentTarget.style.background = "transparent"; e.currentTarget.style.borderColor = "transparent"; }}
    >{value}{suffix}</button>
  );
}

function ModelSelect({ value, onChange, model, muted }) {
  const [open, setOpen] = useState(false);
  return (
    <div style={{ position: "relative" }}>
      <button onClick={() => setOpen((o) => !o)}
        style={{
          display: "flex", alignItems: "center", gap: 8,
          width: "100%", padding: "5px 8px",
          background: "transparent",
          border: "1px solid transparent",
          borderRadius: "var(--r-sm)",
          color: muted ? "var(--text-2)" : "var(--text-1)",
          fontSize: 13,
          transition: "all 120ms ease",
        }}
        onMouseEnter={(e) => { e.currentTarget.style.background = "var(--bg-2)"; e.currentTarget.style.borderColor = "var(--border-s)"; }}
        onMouseLeave={(e) => { e.currentTarget.style.background = "transparent"; e.currentTarget.style.borderColor = "transparent"; }}
      >
        <span style={{
          width: 6, height: 6, borderRadius: 999,
          background: model?.tone === "good" ? "var(--good)" :
                       model?.tone === "warn" ? "var(--warn)" :
                       model?.tone === "info" ? "var(--info)" : "var(--text-3)",
          flex: "none",
        }}/>
        <span className="mono" style={{ flex: 1, textAlign: "left", minWidth: 0, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
          {value}
        </span>
        <I.Down size={11} style={{ color: "var(--text-4)" }}/>
      </button>
      {open && (
        <>
          <div onClick={() => setOpen(false)} style={{ position: "fixed", inset: 0, zIndex: 9 }}/>
          <div style={{
            position: "absolute", top: "calc(100% + 4px)", left: 0,
            minWidth: 240, padding: 4,
            background: "var(--bg-1)",
            border: "1px solid var(--border-m)",
            borderRadius: "var(--r-md)",
            boxShadow: "0 16px 40px -16px oklch(0 0 0 / 0.7)",
            zIndex: 10,
          }}>
            {MODELS.map((m) => (
              <button key={m.id} onClick={() => { onChange(m.id); setOpen(false); }}
                style={{
                  display: "flex", alignItems: "center", gap: 10,
                  width: "100%", padding: "8px 10px",
                  background: m.id === value ? "var(--bg-2)" : "transparent",
                  border: "none", borderRadius: 6,
                  color: "var(--text-1)", fontSize: 13,
                  textAlign: "left",
                }}
                onMouseEnter={(e) => { if (m.id !== value) e.currentTarget.style.background = "var(--bg-2)"; }}
                onMouseLeave={(e) => { if (m.id !== value) e.currentTarget.style.background = "transparent"; }}
              >
                <span style={{
                  width: 6, height: 6, borderRadius: 999,
                  background: m.tone === "good" ? "var(--good)" : m.tone === "warn" ? "var(--warn)" : "var(--info)",
                }}/>
                <span style={{ flex: 1 }}>
                  <div>{m.name}</div>
                  <div className="mono" style={{ fontSize: 11, color: "var(--text-4)" }}>{m.id}</div>
                </span>
                <span style={{ fontSize: 11, color: "var(--text-3)" }}>{m.provider}</span>
                {m.id === value && <I.Check size={13} style={{ color: "var(--accent)" }}/>}
              </button>
            ))}
          </div>
        </>
      )}
    </div>
  );
}

function PriorityChip({ value, onChange }) {
  return (
    <div style={{
      display: "inline-flex", alignItems: "center",
      background: "var(--bg-2)",
      border: "1px solid var(--border-s)",
      borderRadius: 999,
    }}>
      <button onClick={() => onChange(Math.max(1, value - 1))}
        style={chipBtn()}><I.Up size={11} style={{ transform: "rotate(-90deg)" }}/></button>
      <span className="mono" style={{ minWidth: 22, textAlign: "center", fontSize: 12, color: "var(--text-1)", fontWeight: 600 }}>
        P{value}
      </span>
      <button onClick={() => onChange(value + 1)}
        style={chipBtn()}><I.Down size={11} style={{ transform: "rotate(-90deg)" }}/></button>
    </div>
  );
}
function chipBtn() {
  return {
    width: 20, height: 22,
    display: "inline-flex", alignItems: "center", justifyContent: "center",
    background: "transparent", border: "none",
    color: "var(--text-3)",
    cursor: "pointer",
  };
}

function Toggle2({ on, onChange }) {
  return (
    <button onClick={() => onChange(!on)}
      style={{
        position: "relative",
        width: 30, height: 17,
        background: on ? "var(--accent)" : "var(--bg-3)",
        borderRadius: 999,
        border: "none",
        transition: "background 160ms ease",
        cursor: "pointer",
      }}>
      <span style={{
        position: "absolute", top: 2, left: on ? 15 : 2,
        width: 13, height: 13, borderRadius: 999,
        background: on ? "oklch(0.18 0.04 170)" : "var(--text-2)",
        transition: "left 160ms ease",
      }}/>
    </button>
  );
}

function RoutingPreview({ rules }) {
  const probes = [
    { task: "chat.default",         q: "What are my open positions?" },
    { task: "summarise.long",       q: "Summarise this 12k-word strategy doc" },
    { task: "news.interpret",       q: "Decode the latest Fed minutes for me" },
  ];

  return (
    <Card title="Routing preview" subtitle="What Pi will pick right now for each task class">
      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 12 }}>
        {probes.map((p) => {
          const rule = rules.find((r) => r.enabled && r.task === p.task);
          return (
            <div key={p.task} style={{
              padding: 14,
              background: "var(--bg-0)",
              border: "1px solid var(--border-s)",
              borderRadius: "var(--r-md)",
            }}>
              <div style={{ fontSize: 12, color: "var(--text-3)" }}>"{p.q}"</div>
              <div className="mono" style={{ fontSize: 11, color: "var(--accent)", marginTop: 6 }}>→ {p.task}</div>
              {rule ? (
                <div style={{ marginTop: 10, display: "flex", alignItems: "center", gap: 8, fontSize: 12.5 }} className="mono">
                  <span style={{ color: "var(--text-1)" }}>{rule.primary}</span>
                  <span style={{ color: "var(--text-4)" }}>→</span>
                  <span style={{ color: "var(--text-3)" }}>{rule.fallback}</span>
                </div>
              ) : (
                <div style={{ marginTop: 10, fontSize: 12, color: "var(--warn)" }}>
                  <I.Warn size={12} style={{ verticalAlign: "-2px" }}/> No active rule
                </div>
              )}
              {rule && (
                <div style={{ marginTop: 4, fontSize: 11, color: "var(--text-4)" }} className="mono">
                  budget {rule.maxLatencyMs}ms · P{rule.priority}
                </div>
              )}
            </div>
          );
        })}
      </div>
    </Card>
  );
}

window.LlmConfigPanel = LlmConfigPanel;
