<script>
  import { onMount } from "svelte";
  import { api } from "../api.js";
  import Icon from "../Icon.svelte";
  import StatusBadge from "../StatusBadge.svelte";

  let agents = $state([]);
  let options = $state({ providers: [], models: [], tools: [], skills: [] });
  let loading = $state(true);
  let error = $state("");
  let editing = $state(null);
  let editingError = $state("");
  let saving = $state(false);
  let reloading = $state(false);
  let reloadStatus = $state(null);
  let pollTimer = null;
  let { notify } = $props();

  const phaseBadge = $derived.by(() => {
    if (!reloadStatus) return "ok";
    const map = { active: "ok", preparing: "run", draining: "run", activating: "run", failed: "fail" };
    return map[reloadStatus.phase] || "ok";
  });

  const phaseLabel = $derived.by(() => {
    if (!reloadStatus) return "";
    const map = { active: "运行中", preparing: "准备中", draining: "等待任务完成", activating: "激活中", failed: "失败" };
    return map[reloadStatus.phase] || reloadStatus.phase;
  });

  const blank = () => ({
    id: "",
    description: "",
    provider: "",
    model: "",
    token_limit: null,
    max_tool_iterations: null,
    tools: [],
    skills: [],
    delegateMode: "default",
    delegates: [],
    role_prompt: "",
    enabled: true,
  });

  async function load() {
    loading = true;
    error = "";
    try {
      const [a, o] = await Promise.all([
        api("/api/agents"),
        api("/api/agents/options"),
      ]);
      agents = a.agents || [];
      options = o;
    } catch (caught) {
      error = caught.message;
    } finally {
      loading = false;
    }
  }

  async function reload() {
    reloading = true;
    try {
      const result = await api("/api/config/reload", { method: "POST" });
      notify(result.message || "已触发热重载");
      await pollReloadStatus();
    } catch (caught) {
      notify(caught.message, true);
    } finally {
      reloading = false;
    }
  }

  async function pollReloadStatus() {
    try {
      const prev = reloadStatus?.phase;
      reloadStatus = await api("/api/config/reload/status");
      if (reloadStatus.phase === "active" && prev && prev !== "active") {
        await load();
      }
    } catch {}
  }

  function startPolling() {
    stopPolling();
    pollReloadStatus();
    pollTimer = setInterval(pollReloadStatus, 3000);
  }

  function stopPolling() {
    if (pollTimer) { clearInterval(pollTimer); pollTimer = null; }
  }

  function toggleTool(list, name) {
    const i = list.indexOf(name);
    if (i >= 0) list.splice(i, 1);
    else list.push(name);
  }

  function startNew() {
    editing = blank();
    editingError = "";
  }

  function editAgent(agent) {
    const delegates = agent.delegates;
    let delegateMode = "default";
    let list = [];
    if (delegates == null) {
      delegateMode = "default";
    } else if (delegates.includes("*")) {
      delegateMode = "any";
    } else if (delegates.length === 0) {
      delegateMode = "none";
    } else {
      delegateMode = "list";
      list = [...delegates];
    }
    // Fixing a definition should re-enable it by default.
    editing = {
      id: agent.id,
      description: agent.description || "",
      provider: agent.provider || "",
      model: agent.model || "",
      token_limit: agent.token_limit ?? null,
      max_tool_iterations: agent.max_tool_iterations ?? null,
      tools: [...(agent.tools || [])],
      skills: [...(agent.skills || [])],
      delegateMode,
      delegates: list,
      role_prompt: agent.role_prompt || "",
      enabled: agent.load_error || agent.parse_error ? true : agent.enabled !== false,
    };
    editingError = agent.load_error || agent.parse_error || "";
  }

  function cancelEdit() {
    editing = null;
    editingError = "";
  }

  function delegateLabel(agent) {
    const d = agent.delegates;
    if (d == null) return "委托: general-purpose（默认）";
    if (d.includes("*")) return "委托: 任意子代理";
    if (d.length === 0) return "不可继续委托";
    return `委托: ${d.join(", ")}`;
  }

  async function save() {
    if (!editing.id.trim()) {
      notify("请填写 Agent ID", true);
      return;
    }
    if (!editing.description.trim()) {
      notify("请填写描述", true);
      return;
    }
    if (!editing.role_prompt.trim()) {
      notify("请填写角色正文（role）", true);
      return;
    }
    if (!editing.provider || !editing.model) {
      notify("请选择 provider 和 model", true);
      return;
    }
    saving = true;
    try {
      const payload = {
        id: editing.id,
        description: editing.description,
        provider: editing.provider || null,
        model: editing.model || null,
        token_limit: editing.token_limit,
        max_tool_iterations: editing.max_tool_iterations,
        tools: editing.tools,
        skills: editing.skills,
        role_prompt: editing.role_prompt,
        enabled: editing.enabled,
      };
      if (editing.delegateMode === "none") payload.delegates = [];
      else if (editing.delegateMode === "any") payload.delegates = ["*"];
      else if (editing.delegateMode === "list") payload.delegates = editing.delegates;
      await api("/api/agents", { method: "POST", body: JSON.stringify(payload) });
      editing = null;
      notify("子代理已保存，点击「热重载」使其生效");
      await load();
    } catch (caught) {
      notify(caught.message, true);
    } finally {
      saving = false;
    }
  }

  async function toggleEnabled(agent) {
    try {
      await api("/api/agents", {
        method: "POST",
        body: JSON.stringify({
          id: agent.id,
          description: agent.description || "",
          provider: agent.provider || null,
          model: agent.model || null,
          token_limit: agent.token_limit ?? null,
          max_tool_iterations: agent.max_tool_iterations ?? null,
          tools: agent.tools || [],
          skills: agent.skills || [],
          role_prompt: agent.role_prompt || "",
          enabled: !agent.enabled,
        }),
      });
      agent.enabled = !agent.enabled;
      notify(agent.enabled ? "已启用" : "已禁用");
    } catch (caught) {
      notify(caught.message, true);
    }
  }

  async function remove(agent) {
    if (!confirm(`确定删除子代理「${agent.id}」吗？`)) return;
    try {
      await api(`/api/agents/${encodeURIComponent(agent.id)}`, { method: "DELETE" });
      notify("已删除");
      await load();
    } catch (caught) {
      notify(caught.message, true);
    }
  }

  function toolDesc(name) {
    const tool = options.tools.find((t) => t.name === name);
    return tool?.description || "";
  }

  onMount(() => {
    load();
    startPolling();
    return stopPolling;
  });
</script>

<div class="definitions">
  <div class="toolbar">
    <div>
      <h2 style="margin:0">具名子代理</h2>
      <p style="margin:2px 0 0;color:var(--muted);font-size:12px">
        子代理由 <code>~/.picobot/agents/*.md</code> 定义；工具、Skill、Provider 与模型在此直接指定。保存后点击「热重载」使改动生效。
      </p>
    </div>
    <div class="toolbar-actions">
      {#if reloadStatus}
        <span class="badge {phaseBadge}" title={reloadStatus.last_error || ""}>{phaseLabel}</span>
      {/if}
      <button class="secondary" onclick={reload} disabled={reloading}><Icon name="refresh" size={15} />{reloading ? "重载中…" : "热重载"}</button>
      <button class="primary" onclick={startNew}><Icon name="add" size={16} />新增子代理</button>
    </div>
  </div>

  {#if loading}
    <div class="loading">加载中…</div>
  {:else if error}
    <div class="empty-card error-text">{error}</div>
  {:else if agents.length === 0}
    <div class="empty-card">暂无子代理定义</div>
  {:else}
    <div class="cards">
      {#each agents as agent (agent.id)}
        <article class="card">
          <div class="card-row">
            <div>
              <h3>{agent.id} <StatusBadge status={agent.enabled ? "enabled" : "disabled"} /></h3>
              <p>{agent.description || "（无描述）"}</p>
              <div class="meta">
                <span>provider: {agent.provider || agent.llm_profile || "—"}</span>
                <span>model: {agent.model || "—"}</span>
                {#if agent.tools?.length}<span>{agent.tools.length} 个工具</span>{/if}
                {#if agent.skills?.length}<span>{agent.skills.length} 个 Skill</span>{/if}
                <span>{delegateLabel(agent)}</span>
              </div>
              {#if agent.tools?.length}
                <div class="tag-row">
                  {#each agent.tools as tool (tool)}<span class="tag" title={toolDesc(tool)}>{tool}</span>{/each}
                </div>
              {/if}
              {#if agent.load_error || agent.parse_error}
                <div class="agent-error">
                  <Icon name="warning" size={14} />
                  <span>定义错误，已停用：{agent.load_error || agent.parse_error}</span>
                </div>
              {/if}
            </div>
            <div class="card-actions">
              <button class="secondary" onclick={() => editAgent(agent)}><Icon name="more" size={15} />编辑</button>
              {#if !agent.load_error && !agent.parse_error}
                <button class="switch" data-state={agent.enabled ? "checked" : "unchecked"} aria-label="启用/禁用" onclick={() => toggleEnabled(agent)}>
                  <span class="switch-thumb" data-state={agent.enabled ? "checked" : "unchecked"}></span>
                </button>
              {/if}
              <button class="icon-button danger" aria-label="删除" onclick={() => remove(agent)}><Icon name="dismiss" size={16} /></button>
            </div>
          </div>
        </article>
      {/each}
    </div>
  {/if}

  {#if editing}
    <button type="button" class="modal-scrim" onclick={cancelEdit} aria-label="关闭" tabindex="-1"></button>
    <div class="modal" role="dialog" aria-label="编辑子代理">
      <div class="editor-head">
        <div><strong>{editing.id ? `编辑 ${editing.id}` : "新增子代理"}</strong><small>保存后点击「热重载」使改动生效</small></div>
        <button class="icon-button" aria-label="关闭" onclick={cancelEdit}><Icon name="dismiss" size={18} /></button>
      </div>
      {#if editingError}
        <div class="agent-error editor-error">
          <Icon name="warning" size={16} />
          <span>此定义当前有误，已停用：{editingError}。请修正后保存，再点击「热重载」使其生效。</span>
        </div>
      {/if}
      <div class="agent-form">
        <div class="form-row">
          <label>ID
            <input bind:value={editing.id} placeholder="general-purpose" disabled={!!agents.find((a) => a.id === editing.id)} spellcheck="false" />
          </label>
          <label>描述
            <input bind:value={editing.description} placeholder="通用目的子代理…" />
          </label>
        </div>
        <div class="form-row">
          <label>Provider
            <select bind:value={editing.provider}>
              <option value="">（选择）</option>
              {#each options.providers as p (p)}<option value={p}>{p}</option>{/each}
            </select>
          </label>
          <label>Model
            <select bind:value={editing.model}>
              <option value="">（选择）</option>
              {#each options.models as m (m.name)}<option value={m.name}>{m.name}{m.token_limit ? ` · ${m.token_limit} tokens` : " · 默认 128K"}</option>{/each}
            </select>
          </label>
        </div>
        <div class="form-row">
          <label>token_limit（可选上限）
            <input type="number" bind:value={editing.token_limit} placeholder="留空使用模型；不能超过模型上限" />
          </label>
          <label>max_tool_iterations
            <input type="number" bind:value={editing.max_tool_iterations} placeholder="99" />
          </label>
        </div>

        <div class="form-label">工具 <small>（普通工具可直接启用；delegate / emit_signal / agent_task 由运行上下文注入）</small></div>
        <div class="tag-row selectable">
          {#each options.tools as tool (tool.name)}
            <button class="tag pick" class:picked={editing.tools.includes(tool.name)} title={tool.description} onclick={() => toggleTool(editing.tools, tool.name)}>{tool.name}</button>
          {/each}
        </div>

        <div class="form-label">Skills <small>（需要工具集中包含 get_skill）</small></div>
        <div class="tag-row selectable">
          {#each options.skills as skill (skill)}
            <button class="tag pick" class:picked={editing.skills.includes(skill)} onclick={() => toggleTool(editing.skills, skill)}>{skill}</button>
          {/each}
        </div>

        <div class="form-label">递归委托 <small>（该子代理可再委托给哪些子代理）</small></div>
        <select bind:value={editing.delegateMode}>
          <option value="default">默认：仅 general-purpose</option>
          <option value="none">不可继续委托</option>
          <option value="any">任意子代理</option>
          <option value="list">指定列表</option>
        </select>
        {#if editing.delegateMode === "list"}
          <div class="tag-row selectable">
            {#each agents.filter((a) => a.id !== editing.id) as agent (agent.id)}
              <button class="tag pick" class:picked={editing.delegates.includes(agent.id)} title={agent.description} onclick={() => toggleTool(editing.delegates, agent.id)}>{agent.id}</button>
            {/each}
          </div>
        {/if}

        <div class="form-label">角色正文</div>
        <textarea bind:value={editing.role_prompt} placeholder="# Role&#10;&#10;你是一名…"></textarea>
      </div>
      <div class="editor-actions">
        <button class="secondary" onclick={cancelEdit} disabled={saving}>取消</button>
        <button class="primary" onclick={save} disabled={saving}>{saving ? "保存中…" : "保存"}</button>
      </div>
    </div>
  {/if}
</div>

<style>
  .tag-row { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
  .tag { padding: 2px 8px; border: 1px solid var(--line); border-radius: 4px; color: var(--text-soft); background: var(--code-bg); font-size: 11px; font-family: var(--font-mono); }
  .tag-row.selectable .tag { cursor: pointer; user-select: none; }
  .tag-row.selectable .tag.picked { border-color: var(--accent-border); color: var(--accent); background: var(--accent-soft); }
  .card-actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
  .card-actions button { white-space: nowrap; flex-shrink: 0; }
  .agent-error { display: flex; align-items: flex-start; gap: 6px; margin-top: 10px; padding: 8px 10px; border: 1px solid var(--danger-border); border-radius: 6px; color: var(--danger); background: color-mix(in srgb, var(--danger) 8%, transparent); font-size: 12px; line-height: 1.5; }
  .editor-error { margin: 14px 18px 0; }
  .toolbar-actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
  .icon-button.danger:hover { color: var(--danger); border-color: var(--danger-border); }
  .modal-scrim { position: fixed; inset: 0; z-index: 40; border: 0; padding: 0; cursor: default; background: rgba(0,0,0,.45); }
  .modal { position: fixed; z-index: 41; top: 6vh; left: 50%; transform: translateX(-50%); width: min(920px, 94vw); max-height: 88vh; overflow: auto; border: 1px solid var(--line-strong); border-radius: 10px; background: var(--panel); box-shadow: var(--shadow-16, var(--shadow-8)); }
  .editor-head { display: flex; align-items: center; justify-content: space-between; padding: 14px 18px; border-bottom: 1px solid var(--line); }
  .editor-head strong { display: block; font-size: 15px; }
  .editor-head small { color: var(--muted); font-size: 11px; }
  .agent-form { display: grid; gap: 14px; padding: 18px; }
  .form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
  label { display: grid; gap: 5px; color: var(--muted); font-size: 12px; }
  input, select, textarea { width: 100%; padding: 8px 10px; border: 1px solid var(--line-strong); border-radius: 6px; color: var(--text); background: var(--panel-2); font-size: 13px; }
  input:focus, select:focus, textarea:focus { border-color: var(--accent); outline: none; }
  textarea { min-height: 360px; resize: vertical; font-family: var(--font-mono); line-height: 1.6; }
  .form-label { color: var(--muted); font-size: 12px; font-weight: 600; }
  .form-label small { font-weight: 400; color: var(--muted); }
  .editor-actions { display: flex; justify-content: flex-end; gap: 10px; padding: 14px 18px; border-top: 1px solid var(--line); }
  @media (max-width: 800px) { .form-row { grid-template-columns: 1fr; } }
</style>
