/* Agenten-Zentrale: Aufträge mit Live-Protokoll, Freigabe, eigene Agenten je
   Projekt, Zugangsschlüssel für externe Agenten. Lädt nach app.js und trägt
   sich dort ein. */
"use strict";

S.hub = { jobs: [], offen: null, agenten: [], agentenPid: null, tab: "auftraege",
          filter: "alle", vorlagen: null };
OHNE_PROJEKT.push("agenten");
TITEL.agenten = "Agenten-Zentrale";
UNTERTITEL.agenten = "Aufträge an das Modell, eigene Agenten, externe Agenten";

const JOB_STATUS = { queued: "wartet auf Start", running: "läuft", wartet: "Freigabe nötig",
                     done: "fertig", failed: "gescheitert", cancelled: "abgebrochen" };
const JOB_ART = { befehl: "Befehl", git: "Git", entwurf: "Projektentwurf", bericht: "Bericht", zusammenfassung: "Zusammenfassung",
                  agent: "Agent", extern: "extern", fragen: "Fragen erzeugen" };
const JOB_ENDE = ["done", "failed", "cancelled"];
const AUSLOESER = { manuell: "von Hand", taeglich: "täglich", woechentlich: "wöchentlich",
                    erwaehnung: "bei @Erwähnung im Projektkanal", besprechung: "nach einer Besprechung" };
const AKTIONEN = { vorgang_anlegen: "Vorgang anlegen", vorgang_aendern: "Vorgang ändern",
                   kommentar: "Kommentar", besprechung: "Besprechung" };

/* -- Daten ------------------------------------------------------------------ */
async function hubLaden() {
  S.hub.jobs = await api("/api/jobs?limit=100");
  S.hub.jobs.forEach((j) => { if (!JOB_ENDE.includes(j.status)) abonnieren(`job:${j.id}`); });
  await agentenLaden();
}

async function agentenLaden() {
  S.hub.agentenPid = S.pid;
  S.hub.agenten = S.pid ? await api(`/api/projects/${S.pid}/agenten`) : [];
}

function hubZahl() {
  const n = S.hub.jobs.filter((j) => j.status === "wartet").length;
  navZahl("agenten", n, `${n} Auftrag/Aufträge warten auf Freigabe`);
}

document.addEventListener("live", (ev) => {
  const e = ev.detail;
  if (!e.job) return;
  const j = S.hub.jobs.find((x) => x.id === e.job);
  if (e.status) {
    if (S.ansicht === "agenten") hubLaden().then(() => { hubZahl(); zeichnen(); }).catch(() => {});
    else if (j) { j.status = e.status; j.result = e.result; hubZahl(); }
    else hubLaden().then(hubZahl).catch(() => {});
  } else if (e.log && j) {
    j.log = (j.log || "") + e.log + "\n";
    const pre = $("#hub-log");
    if (pre && S.hub.offen && S.hub.offen.id === j.id) {
      pre.textContent = j.log;
      pre.scrollTop = pre.scrollHeight;
    }
  }
});

/* -- Ansicht ---------------------------------------------------------------- */
function zeichneHub(ziel) {
  if (S.hub.agentenPid !== S.pid) { agentenLaden().then(zeichnen).catch(() => {}); return; }
  hubZahl();
  const leiste = el("div", "toolbar");
  const tabs = el("div", "tabs");
  tabs.style.margin = "0";
  [["auftraege", "Aufträge"], ["agenten", "Agenten"]].forEach(([name, text]) => {
    const b = el("button", "", text);
    b.type = "button";
    b.setAttribute("aria-selected", String(S.hub.tab === name));
    b.onclick = () => { S.hub.tab = name; zeichnen(); };
    tabs.append(b);
  });
  leiste.append(tabs, el("div", "spacer"));
  ziel.append(leiste);
  if (S.hub.tab === "agenten") zeichneAgenten(ziel, leiste);
  else zeichneAuftraege(ziel, leiste);
}

const jobPille = (j) => {
  const p = el("span", "pill pill--" + j.status, JOB_STATUS[j.status] || j.status);
  return p;
};

function zeichneAuftraege(ziel, leiste) {
  const filter = el("select");
  fuelleAuswahl(filter, [["alle", "Alle"], ["meine", "Meine"], ["wartet", "Freigabe nötig"],
                         ["offen", "Laufende"]], S.hub.filter);
  filter.onchange = () => { S.hub.filter = filter.value; zeichnen(); };
  leiste.append(filter);
  const jobs = S.hub.jobs.filter((j) =>
    S.hub.filter === "alle" ? true
    : S.hub.filter === "meine" ? j.created_by && j.created_by.id === S.me.id
    : S.hub.filter === "wartet" ? j.status === "wartet"
    : !JOB_ENDE.includes(j.status));
  if (!jobs.length) {
    const leer = el("div", "empty");
    leer.append(ico("robot", "solid", "gross"), document.createTextNode(
      "Noch keine Aufträge. Sie entstehen aus KI-Entwurf, Bericht mit Erzählteil, "
      + "„Zusammenfassen“ im Chat, den Agenten eines Projekts oder externen Agenten "
      + "über einen Zugangsschlüssel."));
    ziel.append(leer);
    return;
  }
  const raster = el("div", "hub");
  const tabelle = el("table", "grid");
  tabelle.innerHTML = `<thead><tr><th>Status</th><th>Art</th><th>Auftrag</th><th>Projekt</th>
    <th>Von</th><th>Wann</th></tr></thead>`;
  const koerper = el("tbody");
  jobs.forEach((j) => {
    const tr = el("tr", S.hub.offen && S.hub.offen.id === j.id ? "is-summary" : "");
    const st = el("td");
    st.append(jobPille(j));
    tr.append(st, el("td", "", JOB_ART[j.kind] || j.kind), el("td", "", j.titel),
              el("td", "", j.project || "–"), el("td", "", j.created_by ? j.created_by.name : "–"),
              el("td", "", new Date(j.created_at).toLocaleString("de-DE",
                { day: "2-digit", month: "2-digit", hour: "2-digit", minute: "2-digit" })));
    tr.onclick = () => { S.hub.offen = j; zeichnen(); };
    koerper.append(tr);
  });
  tabelle.append(koerper);
  raster.append(tabelle);
  if (S.hub.offen) {
    const j = S.hub.jobs.find((x) => x.id === S.hub.offen.id);
    if (j) { S.hub.offen = j; raster.append(auftragDetail(j)); }
  }
  ziel.append(raster);
}

function auftragDetail(j) {
  const karte = el("div", "karte hub__detail");
  const kopf = el("div", "toolbar");
  kopf.append(jobPille(j), Object.assign(el("h3", "", j.titel), { style: "margin:0" }),
              el("div", "spacer"));
  if (!JOB_ENDE.includes(j.status)) {
    const stop = knopf("btn btn--danger", "stop", "Abbrechen");
    stop.onclick = async () => {
      try { await api(`/api/jobs/${j.id}/abbrechen`, { method: "POST" }); }
      catch (e) { meldung(e.message, true); }
    };
    kopf.append(stop);
  } else if (j.kind !== "extern") {
    const nochmal = knopf("btn", "rotate", "Wiederholen");
    nochmal.onclick = async () => {
      try {
        const neu = await api(`/api/jobs/${j.id}/wiederholen`, { method: "POST" });
        S.hub.offen = neu;
        await hubLaden();
        zeichnen();
      } catch (e) { meldung(e.message, true); }
    };
    kopf.append(nochmal);
  }
  const zu = knopf("btn btn--ghost", "xmark", "");
  zu.onclick = () => { S.hub.offen = null; zeichnen(); };
  kopf.append(zu);
  karte.append(kopf);
  const meta = [JOB_ART[j.kind] || j.kind, j.project ? "Projekt " + j.project : null,
                j.created_by ? "von " + j.created_by.name : null,
                j.started_at ? "gestartet " + new Date(j.started_at).toLocaleTimeString("de-DE") : null,
                j.finished_at ? "beendet " + new Date(j.finished_at).toLocaleTimeString("de-DE") : null];
  karte.append(el("div", "muted", meta.filter(Boolean).join(" · ")));
  if (j.params && j.params.description) {
    const p = el("p", "", j.params.description);
    p.style.whiteSpace = "pre-wrap";
    karte.append(p);
  }

  const r = j.result || {};
  if (j.status === "wartet" && r.aktionen) {
    const kasten = el("div", "assistent__vorschlaege");
    kasten.style.border = "1px solid var(--line)";
    kasten.style.borderRadius = "8px";
    if (r.text) {
      const t = el("p", "", r.text);
      t.style.whiteSpace = "pre-wrap";
      karte.append(t);
    }
    vorschlagsliste(kasten, r.aktionen, r.verworfen || [], async (nummern) => {
      const antwort = await jsonRuf(`/api/jobs/${j.id}/uebernehmen`, "POST",
                                    { aktionen: nummern.map((n) => r.roh[n]) });
      uebernahmeMelden(antwort);
      if (S.pid === j.project_id) await projektLaden();
      await hubLaden();
      zeichnen();
    }, r.mitglieder || []);
    const weg = knopf("btn btn--ghost", "ban", "Alle verwerfen");
    weg.onclick = async () => {
      try { await api(`/api/jobs/${j.id}/verwerfen`, { method: "POST" }); }
      catch (e) { meldung(e.message, true); }
    };
    kasten.append(weg);
    karte.append(kasten);
  } else if (j.status === "done") {
    if (r.text) {
      const t = el("p", "", r.text);
      t.style.whiteSpace = "pre-wrap";
      karte.append(el("label", "", "Ergebnis"), t);
    }
    if (r.added !== undefined) {
      karte.append(el("div", "", `${r.added} Vorgänge aus „${r.name}“ (Modell ${r.model})`));
    }
    if (r.gespeichert !== undefined) {
      karte.append(el("div", "", `${r.gespeichert} Frage(n) gespeichert, warten auf Freigabe`
        + (r.verworfen ? ` · ${r.verworfen} verworfen` : "")));
    }
    if (r.markdown) {
      const a = el("a", "btn");
      a.href = `/api/jobs/${j.id}/ergebnis`;
      a.append(ico("download"), document.createTextNode(" Bericht herunterladen"));
      karte.append(a);
    }
    if (r.ergebnis) {
      karte.append(el("div", "muted", r.ergebnis.map((e) =>
        `${e.art} ${e.key || ""}: ${e.ok ? "übernommen" : "nicht - " + e.fehler}`).join(" · ")));
    }
    if (j.kind === "extern" && r.exit !== undefined) karte.append(el("div", "muted", `Rückgabewert ${r.exit}`));
  }
  karte.append(el("label", "", "Protokoll"));
  const pre = el("pre", "hub__log", j.log || "(noch nichts)");
  pre.id = "hub-log";
  karte.append(pre);
  setTimeout(() => { pre.scrollTop = pre.scrollHeight; });
  return karte;
}

/* -- Agenten je Projekt ------------------------------------------------------ */
function zeichneAgenten(ziel, leiste) {
  if (!S.pid) {
    ziel.append(el("div", "empty", "Agenten gehören zu einem Projekt – links eines wählen."));
    return;
  }
  const neu = knopf("btn btn--primary", "plus", "Agent");
  neu.onclick = () => oeffneAgent(null);
  const vorlage = el("select");
  vorlage.style.width = "auto";
  fuelleAuswahl(vorlage, [["", "Aus Vorlage …"]], "");
  vorlagenLaden().then((liste) => fuelleAuswahl(vorlage,
    [["", "Aus Vorlage …"]].concat(liste.map((v, i) => [String(i), v.name])), ""));
  vorlage.onchange = () => {
    const v = (S.hub.vorlagen || [])[Number(vorlage.value)];
    if (v) oeffneAgent(null, v);
    vorlage.value = "";
  };
  leiste.append(el("span", "muted", projektInfo(S.pid) ? projektInfo(S.pid).projekt.name : ""),
                vorlage, neu);
  if (!S.hub.agenten.length) {
    const leer = el("div", "empty");
    leer.append(ico("robot", "solid", "gross"), document.createTextNode(
      "Noch kein Agent in diesem Projekt. Ein Agent bekommt einen Auftrag in Worten, "
      + "läuft von Hand, nach Zeitplan oder auf ein Ereignis, schreibt in den Projektkanal "
      + "und kann nur, was seine Besitzerin auch kann. Vorschläge, die etwas ändern, "
      + "warten auf Freigabe."));
    ziel.append(leer);
    return;
  }
  const tabelle = el("table", "grid");
  tabelle.innerHTML = `<thead><tr><th>Agent</th><th>Auslöser</th><th>Darf</th><th>Besitzerin</th>
    <th>Letzter Lauf</th><th></th></tr></thead>`;
  const koerper = el("tbody");
  S.hub.agenten.forEach((a) => {
    const tr = el("tr", a.aktiv ? "" : "is-out");
    const name = el("td");
    name.append(el("b", "", a.name));
    if (!a.aktiv) name.append(" ", el("span", "pill", "abgeschaltet"));
    if (a.autonom) name.append(" ", el("span", "pill", "übernimmt Kommentare selbst"));
    const wann = a.ausloeser === "taeglich" ? `täglich ${a.uhrzeit}`
      : a.ausloeser === "woechentlich" ? `${WOCHENTAGE[a.wochentag]} ${a.uhrzeit}`
      : AUSLOESER[a.ausloeser] || a.ausloeser;
    tr.append(name, el("td", "", wann),
              el("td", "", a.aktionen.length ? a.aktionen.map((x) => AKTIONEN[x] || x).join(", ") : "nur berichten"),
              el("td", "", a.owner ? a.owner.name : "–"),
              el("td", "", a.letzter_lauf ? new Date(a.letzter_lauf).toLocaleString("de-DE",
                { day: "2-digit", month: "2-digit", hour: "2-digit", minute: "2-digit" }) : "–"));
    const aktion = el("td");
    const start = knopf("btn btn--ghost", "play", "Jetzt starten");
    start.onclick = async (e) => {
      e.stopPropagation();
      try {
        const job = await api(`/api/agenten/${a.id}/starten`, { method: "POST" });
        meldung(`Agent „${a.name}“ läuft (Auftrag ${job.id})`);
        S.hub.tab = "auftraege";
        S.hub.offen = job;
        await hubLaden();
        zeichnen();
      } catch (err) { meldung(err.message, true); }
    };
    const bearbeiten = knopf("btn btn--ghost", "pen", "");
    bearbeiten.onclick = (e) => { e.stopPropagation(); oeffneAgent(a); };
    aktion.append(start, bearbeiten);
    tr.append(aktion);
    tr.onclick = () => oeffneAgent(a);
    koerper.append(tr);
  });
  tabelle.append(koerper);
  ziel.append(tabelle);
}

async function vorlagenLaden() {
  if (!S.hub.vorlagen) {
    try { S.hub.vorlagen = await api("/api/agenten/vorlagen"); } catch (e) { S.hub.vorlagen = []; }
  }
  return S.hub.vorlagen;
}

let offenerAgent = null;

function oeffneAgent(a, vorlage) {
  offenerAgent = a;
  const v = a || vorlage || {};
  titelSetzen("#agent-titel", "robot", a ? `Agent „${a.name}“` : "Neuer Agent");
  $("#ag-name").value = v.name || "";
  $("#ag-prompt").value = v.prompt || "";
  document.querySelectorAll("#ag-aktionen input").forEach((box) => {
    box.checked = (v.aktionen || []).includes(box.value);
  });
  $("#ag-ausloeser").value = v.ausloeser || "manuell";
  $("#ag-uhrzeit").value = v.uhrzeit || "07:00";
  $("#ag-wochentag").value = String(v.wochentag || 0);
  $("#ag-autonom").checked = Boolean(v.autonom);
  $("#ag-aktiv").checked = a ? a.aktiv : true;
  $("#ag-delete").hidden = !a;
  agentZeitfelder();
  $("#dlg-agent").showModal();
}

function agentZeitfelder() {
  const art = $("#ag-ausloeser").value;
  $("#ag-zeit").hidden = !["taeglich", "woechentlich"].includes(art);
  $("#ag-wochentag").disabled = art !== "woechentlich";
}

document.addEventListener("DOMContentLoaded", () => {
  $("#ag-ausloeser").onchange = agentZeitfelder;
  $("#dlg-agent form").onsubmit = async (e) => {
    e.preventDefault();
    const koerper = {
      name: $("#ag-name").value.trim(), prompt: $("#ag-prompt").value.trim(),
      aktionen: [...document.querySelectorAll("#ag-aktionen input:checked")].map((b) => b.value),
      ausloeser: $("#ag-ausloeser").value, uhrzeit: $("#ag-uhrzeit").value || "07:00",
      wochentag: Number($("#ag-wochentag").value || 0),
      autonom: $("#ag-autonom").checked, aktiv: $("#ag-aktiv").checked,
    };
    if (!koerper.name) { meldung("Bitte einen Namen angeben.", true); return; }
    try {
      if (offenerAgent) await jsonRuf(`/api/agenten/${offenerAgent.id}`, "PATCH", koerper);
      else await jsonRuf(`/api/projects/${S.pid}/agenten`, "POST", koerper);
      $("#dlg-agent").close();
      await agentenLaden();
      zeichnen();
      meldung("Agent gespeichert");
    } catch (err) { meldung(err.message, true); }
  };
  $("#ag-delete").onclick = async () => {
    if (!offenerAgent || !confirm(`Agent „${offenerAgent.name}“ löschen?`)) return;
    try {
      await api(`/api/agenten/${offenerAgent.id}`, { method: "DELETE" });
      $("#dlg-agent").close();
      await agentenLaden();
      zeichnen();
    } catch (err) { meldung(err.message, true); }
  };
});

/* -- Anschlüsse an Chat und Einstellungen ----------------------------------- */
document.addEventListener("kanal-kopf", (ev) => {
  if (!S.me.module.agenten) return;
  const { kanal, ziel } = ev.detail;
  const b = knopf("btn btn--ghost", "wand-magic-sparkles", "Zusammenfassen");
  b.title = "Die letzten 100 Nachrichten vom lokalen Modell zusammenfassen lassen";
  b.onclick = async () => {
    b.disabled = true;
    try {
      const job = await jsonRuf("/api/jobs", "POST",
                                { kind: "zusammenfassung", params: { kanal_id: kanal.id } });
      meldung(`Zusammenfassung läuft (Auftrag ${job.id}) – ein bis drei Minuten`);
      aufJob(job.id, (fertig) => {
        b.disabled = false;
        if (fertig.status !== "done") { meldung("Zusammenfassung: " + (letzteLogzeile(fertig) || fertig.status), true); return; }
        if (S.chat.offen && S.chat.offen.id === kanal.id && S.ansicht === "chat") {
          nachrichtAnhaengen({ id: 0, author: { id: 0, name: "Zusammenfassung", avatar: null },
                               body: fertig.result.text, created_at: new Date().toISOString() });
        } else meldung("Zusammenfassung fertig – in der Agenten-Zentrale nachlesbar");
      });
    } catch (e) { meldung(e.message, true); b.disabled = false; }
  };
  ziel.append(b);
});

document.addEventListener("einstellungen-gezeichnet", (ev) => {
  if (!S.me.module.agenten) return;
  const karte = el("div", "karte");
  karte.append(kartenKopf("key", "Zugangsschlüssel für externe Agenten"),
    el("p", "muted", "Ein Skript oder Claude Code meldet sich damit in der Zentrale an, "
      + "legt einen Auftrag an und schreibt sein Protokoll hinein – „Abbrechen“ dort "
      + "beendet es. Der Schlüssel wird genau einmal gezeigt."));
  const liste = el("div");
  const zeichneTokens = async () => {
    liste.replaceChildren();
    let tokens = [];
    try { tokens = await api("/api/tokens"); } catch (e) { return; }
    tokens.forEach((t) => {
      const z = el("div", "slot");
      z.append(el("div", "slot__zeit", kurzDatum(t.created_at)),
               el("div", "slot__inhalt", `${t.name}${t.last_used ? " · zuletzt " + kurzDatum(t.last_used) : " · noch nie benutzt"}`));
      const weg = knopf("btn btn--ghost", "trash", "");
      weg.onclick = async () => {
        if (!confirm(`Schlüssel „${t.name}“ zurückziehen?`)) return;
        try { await api(`/api/tokens/${t.id}`, { method: "DELETE" }); zeichneTokens(); }
        catch (e) { meldung(e.message, true); }
      };
      z.append(weg);
      liste.append(z);
    });
  };
  const form = el("form");
  form.style.display = "flex";
  form.style.gap = "8px";
  form.style.alignItems = "flex-end";
  const feld = el("input");
  feld.type = "text";
  feld.placeholder = "Bezeichnung, z. B. Claude Code";
  feld.maxLength = 80;
  const los = knopf("btn", "plus", "Schlüssel erzeugen");
  los.type = "submit";
  form.append(feld, los);
  const anzeige = el("input");
  anzeige.type = "text";
  anzeige.readOnly = true;
  anzeige.hidden = true;
  anzeige.style.marginTop = "8px";
  form.onsubmit = async (e) => {
    e.preventDefault();
    try {
      const t = await jsonRuf("/api/tokens", "POST", { name: feld.value.trim() });
      anzeige.value = t.token;
      anzeige.hidden = false;
      anzeige.select();
      feld.value = "";
      meldung("Schlüssel erzeugt – jetzt kopieren, er wird nicht wieder gezeigt");
      zeichneTokens();
    } catch (err) { meldung(err.message, true); }
  };
  const hinweis = el("pre", "hub__log", "MINERVA_URL=" + location.origin
    + " MINERVA_TOKEN=… scripts/agent_melden.sh <projekt_id> claude -p \"Tests reparieren\"");
  karte.append(liste, form, anzeige, el("label", "", "So meldet sich ein externer Agent"), hinweis);
  ev.detail.ziel.append(karte);
  zeichneTokens();
});

/* -- Eintragen -------------------------------------------------------------- */
ZEICHNER.agenten = zeichneHub;
LADER.agenten = hubLaden;
document.addEventListener("app-gestartet", () => {
  if (S.me && S.me.module.agenten && S.ansicht !== "agenten") {
    hubLaden().then(hubZahl).catch(() => { /* Zentrale ist keine Startbedingung */ });
  }
});
