/* Schale wie in VS Code: Kategorien (Leiste links), Seitenleiste mit
   Abschnitten, Reiter für Ansichten und Dateien, untere Leiste, Statuszeile.
   Lädt nach app.js und den Erweiterungen. Die Leisten hat Jinja aus den
   Beiträgen der Manifeste gezeichnet (#beitraege) - hier werden sie belebt.
   Erweiterungen tragen sich in dieselben Tabellen ein wie in app.js:
     ABSCHNITT_ZEICHNER["dateien.explorer"] = (ziel, aktionen) => …
     UNTEN_ZEICHNER.konsole = { titel, symbol, zeichne(ziel) }
     BEFEHLE["werkstatt.suchen"] = () => … */
"use strict";

const BEFEHLE = {};                  // befehl-id -> fn()
const ABSCHNITT_ZEICHNER = {};       // abschnitt-id -> fn(ziel, aktionen) für art baum|eigen
const UNTEN_ZEICHNER = {};           // reiter-id -> { titel, symbol, zeichne(ziel), nur_desktop }
S.tabs = { liste: [], aktiv: null };
S.schale = { aktivitaet: null, panelBreite: 0, untenHoehe: 0, unten: { tab: null }, bereit: false,
             gemerkt: null };

const SCHALE_KEY = () => `minerva.schale.${S.pid || 0}`;
const ansichtInfo = (id) => BEITRAEGE.ansichten.find((a) => a.id === id);
function aktivitaetVon(ansicht) {
  const a = $(`.panel a[data-view="${ansicht}"]`);
  return a ? a.closest(".panel__gruppe").dataset.aktivitaet : null;
}

/* -- Kategorien und Abschnitte -------------------------------------------- */
function aktivitaetWechseln(id) {
  const schale = $("#schale");
  if (!$(`.panel__gruppe[data-aktivitaet="${id}"]`)) return;
  schale.classList.remove("panel-zu");
  S.schale.aktivitaet = id;
  document.querySelectorAll(".panel__gruppe").forEach((g) => { g.hidden = g.dataset.aktivitaet !== id; });
  document.querySelectorAll("#aktiv button[data-aktivitaet]").forEach((b) =>
    b.classList.toggle("is-active", b.dataset.aktivitaet === id));
  schaleSpeichern();
}

function panelUmschalten(offen) {
  const schale = $("#schale");
  const zu = offen === undefined ? !schale.classList.contains("panel-zu") : !offen;
  schale.classList.toggle("panel-zu", zu);
  if (!zu) schale.classList.add("panel-offen");
  schaleSpeichern();
}

/** Zahl an einer Kategorie: Summe der sichtbaren Zahlen ihrer Einträge. */
function aktivZahl(aktivitaet) {
  const knopf = $(`#aktiv button[data-aktivitaet="${aktivitaet}"]`);
  const gruppe = $(`.panel__gruppe[data-aktivitaet="${aktivitaet}"]`);
  if (!knopf || !gruppe) return;
  const summe = [...gruppe.querySelectorAll(".nav__zahl:not([hidden])")]
    .reduce((n, z) => n + (Number(z.textContent) || 0), 0);
  let zahl = $(".nav__zahl", knopf);
  if (!zahl) { zahl = el("span", "nav__zahl"); knopf.append(zahl); }
  zahl.textContent = String(summe);
  zahl.hidden = !summe;
}

function abschnittZeichnen(id) {
  const d = $(`.panel details[data-abschnitt="${id}"]`);
  if (!d || !ABSCHNITT_ZEICHNER[id]) return;
  const inhalt = $(".abschnitt__inhalt", d);
  const aktionen = $(".abschnitt__aktionen", d);
  inhalt.replaceChildren();
  aktionen.replaceChildren();
  ABSCHNITT_ZEICHNER[id](inhalt, aktionen);
  document.dispatchEvent(new CustomEvent("abschnitt-gezeichnet", { detail: { id, ziel: inhalt } }));
}

/* Struktur: der Organisationsbaum aus app.js, samt der drei Anlege-Knöpfe,
   die bindeDialoge() über ihre ids findet. */
ABSCHNITT_ZEICHNER["planung.struktur"] = (ziel, aktionen) => {
  ziel.id = "orgbaum";
  const k = (id, symbol, titel) => {
    const b = el("button");
    b.type = "button"; b.id = id; b.title = titel;
    b.append(ico(symbol));
    return b;
  };
  aktionen.append(k("neues-projekt", "diagram-project", "Projekt anlegen"),
                  k("neuer-bereich", "layer-group", "Arbeitsbereich anlegen"),
                  k("neue-einheit", "plus", "Unternehmen anlegen"));
  baueBaum();
};

/* -- Reiter ---------------------------------------------------------------- */
function ansichtTab(ansicht) {
  const info = ansichtInfo(ansicht) || { titel: TITEL[ansicht] || ansicht, symbol: "window-maximize" };
  return { id: "ansicht:" + ansicht, art: "ansicht", ansicht, titel: info.titel,
           symbol: info.symbol, hash: ansicht };
}

function reiterKopf(tab) {
  const k = el("div", "reiter__tab");
  k.setAttribute("role", "tab");
  k.append(ico(tab.symbol), el("span", "reiter__titel", tab.titel));
  const zu = el("button", "reiter__zu");
  zu.type = "button";
  zu.title = "Schließen";
  zu.append(ico("xmark"));
  zu.onclick = (e) => { e.stopPropagation(); schliesseTab(tab.id); };
  k.append(zu);
  k.onclick = () => {
    $("#schale").classList.remove("panel-offen");
    if (tab.art === "ansicht") wechsle(tab.ansicht); else aktiviereTab(tab.id);
  };
  k.onauxclick = (e) => { if (e.button === 1) { e.preventDefault(); schliesseTab(tab.id); } };
  return bedienbar(k, tab.titel);
}

function oeffneTabStill(def) {
  let tab = S.tabs.liste.find((t) => t.id === def.id);
  if (tab) return tab;
  tab = { ...def, el: el("div", "tab-inhalt " + (def.art === "ansicht" ? "content" : "tab-inhalt--datei")),
          dreckig: false, gerendert: false };
  tab.el.hidden = true;
  tab.kopf = reiterKopf(tab);
  $("#tab-inhalte").append(tab.el);
  $("#reiter").append(tab.kopf);
  S.tabs.liste.push(tab);
  return tab;
}

function oeffneTab(def) {
  const tab = oeffneTabStill(def);
  aktiviereTab(tab.id);
  return tab;
}

function aktiviereTab(id) {
  const tab = S.tabs.liste.find((t) => t.id === id);
  if (!tab) return;
  S.tabs.liste.forEach((t) => {
    t.el.hidden = t !== tab;
    t.kopf.classList.toggle("is-active", t === tab);
    t.kopf.setAttribute("aria-selected", String(t === tab));
  });
  S.tabs.aktiv = tab;
  if (tab.art === "ansicht") {
    // #inhalt wandert mit der vorderen Ansicht: Treiber und Altcode finden sie so.
    const alt = document.getElementById("inhalt");
    if (alt && alt !== tab.el) alt.removeAttribute("id");
    tab.el.id = "inhalt";
    S.ansicht = tab.ansicht;
    $(".head").hidden = false;
  } else {
    $(".head").hidden = true;
    if (!tab.gerendert) { tab.gerendert = true; tab.render(tab.el, tab); }
  }
  tab.kopf.scrollIntoView({ block: "nearest", inline: "nearest" });
  if (tab.art !== "ansicht") urlAngleichen(true);
  document.dispatchEvent(new CustomEvent("tab-gewechselt", { detail: { tab } }));
  statusZeichnen();
  schaleSpeichern();
}

async function schliesseTab(id, erzwingen = false) {
  const tab = S.tabs.liste.find((t) => t.id === id);
  if (!tab) return false;
  if (!erzwingen && tab.schliessen && !(await tab.schliessen(tab))) return false;
  const i = S.tabs.liste.indexOf(tab);
  S.tabs.liste.splice(i, 1);
  tab.el.remove();
  tab.kopf.remove();
  if (tab.aufraeumen) tab.aufraeumen(tab);      // Editor und Modell freigeben
  if (S.tabs.aktiv === tab) {
    S.tabs.aktiv = null;
    const nachbar = S.tabs.liste[i] || S.tabs.liste[i - 1];
    if (!nachbar) wechsle(ANSICHTEN.includes("tag") ? "tag" : ANSICHTEN[0]);
    else if (nachbar.art === "ansicht") wechsle(nachbar.ansicht);
    else aktiviereTab(nachbar.id);
  }
  schaleSpeichern();
  return true;
}

function tabAendern(id, { titel, dreckig } = {}) {
  const tab = S.tabs.liste.find((t) => t.id === id);
  if (!tab) return;
  if (titel !== undefined) { tab.titel = titel; $(".reiter__titel", tab.kopf).textContent = titel; }
  if (dreckig !== undefined) { tab.dreckig = dreckig; tab.kopf.classList.toggle("is-dreckig", dreckig); }
}

const aktiverTab = () => S.tabs.aktiv;

function naechsterTab(schritt) {
  const n = S.tabs.liste.length;
  if (n < 2 || !S.tabs.aktiv) return;
  const i = (S.tabs.liste.indexOf(S.tabs.aktiv) + schritt + n) % n;
  S.tabs.liste[i].kopf.click();
}

/** Aktiven Menüpunkt und seine Kategorie markieren; die Seitenleiste folgt
    einer Ansicht, die in einer anderen Kategorie liegt (Direktlink, Reiter). */
function schaleMarkiere() {
  const vorne = S.tabs.aktiv && S.tabs.aktiv.art === "ansicht";
  document.querySelectorAll(".panel a[data-view]").forEach((a) =>
    a.classList.toggle("is-active", vorne && a.dataset.view === S.ansicht));
  const gruppe = aktivitaetVon(S.ansicht);
  if (vorne && gruppe && gruppe !== S.schale.aktivitaet) aktivitaetWechseln(gruppe);
  statusZeichnen();
}

/* -- untere Leiste --------------------------------------------------------- */
function untenUmschalten(offen, tabId) {
  const u = $("#unten");
  u.hidden = offen === undefined ? !u.hidden : !offen;
  if (!u.hidden) {
    const erster = Object.keys(UNTEN_ZEICHNER).find((k) => untenSichtbar(k));
    untenTab(UNTEN_ZEICHNER[tabId] ? tabId : (S.schale.unten.tab || erster));
  }
  schaleSpeichern();
}

const untenSichtbar = (id) => UNTEN_ZEICHNER[id]
  && (!UNTEN_ZEICHNER[id].nur_desktop || Boolean(S.me && S.me.befehle));

function untenTab(id) {
  if (!untenSichtbar(id)) { $("#unten").hidden = true; return; }
  $("#unten").hidden = false;                   // einen Reiter wählen heißt: Leiste auf
  S.schale.unten.tab = id;
  const leiste = $("#unten-reiter");
  leiste.replaceChildren();
  Object.entries(UNTEN_ZEICHNER).forEach(([k, r]) => {
    if (!untenSichtbar(k)) return;
    const b = el("button", "reiter__tab" + (k === id ? " is-active" : ""));
    b.type = "button";
    b.setAttribute("role", "tab");
    b.append(ico(r.symbol), el("span", "reiter__titel", r.titel));
    b.onclick = () => untenTab(k);
    leiste.append(b);
  });
  const zu = el("button", "reiter__zu");
  zu.type = "button";
  zu.title = "Leiste schließen";
  zu.append(ico("xmark"));
  zu.onclick = () => untenUmschalten(false);
  leiste.append(el("span", "spacer"), zu);
  const ziel = $("#unten-inhalt");
  ziel.replaceChildren();
  UNTEN_ZEICHNER[id].zeichne(ziel);
  schaleSpeichern();
}

/* -- Statuszeile ----------------------------------------------------------- */
function statusZeichnen() {
  const s = $("#status");
  if (!s) return;
  s.replaceChildren();
  const links = el("span", "status__links");
  const live = el("span", "status__punkt" + (S.live && S.live.readyState === 1 ? " is-an" : ""));
  live.title = S.live && S.live.readyState === 1 ? "Live verbunden" : "Keine Live-Verbindung";
  links.append(live, el("span", "", S.daten ? S.daten.project.name : "Kein Projekt"));
  if (S.tabs.aktiv && S.tabs.aktiv.art !== "ansicht") links.append(el("span", "", S.tabs.aktiv.titel));
  const rechts = el("span", "status__rechts");
  const info = el("span");
  info.id = "status-info";
  const k = (symbol, titel, fn) => {
    const b = el("button");
    b.type = "button"; b.title = titel;
    b.append(ico(symbol));
    b.onclick = fn;
    return b;
  };
  rechts.append(info, k("table-columns", "Seitenleiste ein/aus (Strg+B)", () => panelUmschalten()),
                k("terminal", "Untere Leiste ein/aus (Strg+J)", () => untenUmschalten()),
                k("robot", "Assistent", () => assistentUmschalten()));
  s.append(links, rechts);
}

/* -- Merken und Wiederherstellen ------------------------------------------- */
function schaleSpeichern() {
  if (!S.schale.bereit) return;
  const zu = [...document.querySelectorAll(".panel details[data-abschnitt]:not([open])")]
    .map((d) => d.dataset.abschnitt);
  const daten = {
    aktivitaet: S.schale.aktivitaet, panelBreite: S.schale.panelBreite,
    panelZu: $("#schale").classList.contains("panel-zu"), zu,
    tabs: S.tabs.liste.map((t) => t.art === "ansicht" ? { art: "ansicht", ansicht: t.ansicht }
                                                       : { art: t.art, pfad: t.pfad }),
    aktiv: S.tabs.aktiv ? S.tabs.aktiv.id : null,
    unten: { offen: !$("#unten").hidden, hoehe: S.schale.untenHoehe, tab: S.schale.unten.tab },
  };
  try { localStorage.setItem(SCHALE_KEY(), JSON.stringify(daten)); } catch (e) { /* privater Modus */ }
}

function schaleLesen() {
  try { return JSON.parse(localStorage.getItem(SCHALE_KEY()) || "null"); } catch (e) { return null; }
}

/** Reiter und Leisten des Projekts wiederherstellen; Dateireiter eines anderen
    Projekts schließen. Gibt das Gemerkte zurück (starten() braucht den vorderen Reiter). */
function schaleWiederherstellen() {
  const war = S.schale.bereit;
  S.schale.bereit = false;                       // nicht bei jedem Schritt zwischenspeichern
  S.tabs.liste.filter((t) => t.art !== "ansicht" && t.pid !== S.pid)
    .forEach((t) => schliesseTab(t.id, true));
  const d = schaleLesen();
  if (d) {
    if (d.panelBreite) panelBreiteSetzen(d.panelBreite);
    $("#schale").classList.toggle("panel-zu", Boolean(d.panelZu));
    document.querySelectorAll(".panel details[data-abschnitt]").forEach((det) => {
      det.open = !(d.zu || []).includes(det.dataset.abschnitt);
    });
    (d.tabs || []).forEach((t) => {
      if (t.art === "ansicht" && ANSICHTEN.includes(t.ansicht)) oeffneTabStill(ansichtTab(t.ansicht));
      else if (t.pfad && typeof dateiTab === "function") oeffneTabStill(dateiTab(t.pfad));
    });
    if (d.unten && d.unten.hoehe) untenHoeheSetzen(d.unten.hoehe);
    if (d.aktivitaet) aktivitaetWechseln(d.aktivitaet);
    if (d.unten && d.unten.offen) untenUmschalten(true, d.unten.tab);
  }
  S.schale.bereit = war || true;
  S.schale.gemerkt = d;
  return d;
}

/* -- Griffe ---------------------------------------------------------------- */
function panelBreiteSetzen(px) {
  S.schale.panelBreite = Math.max(180, Math.min(480, px));
  $("#schale").style.setProperty("--panel-breite", S.schale.panelBreite + "px");
}
function untenHoeheSetzen(px) {
  S.schale.untenHoehe = Math.max(80, Math.min(window.innerHeight - 160, px));
  $("#schale").style.setProperty("--unten-hoehe", S.schale.untenHoehe + "px");
}
function griffBinden(griff, aufBewegung) {
  griff.onpointerdown = (e) => {
    e.preventDefault();
    griff.classList.add("is-aktiv");
    griff.setPointerCapture(e.pointerId);
    griff.onpointermove = (ev) => aufBewegung(ev);
    griff.onpointerup = () => {
      griff.onpointermove = null;
      griff.classList.remove("is-aktiv");
      schaleSpeichern();
    };
  };
}

/* -- Tastenkürzel ---------------------------------------------------------- */
/** "Ctrl+Shift+F" aus einem Manifest → passt das Ereignis? Cmd zählt als Ctrl. */
function tasteTrifft(kuerzel, e) {
  const teile = kuerzel.toLowerCase().split("+");
  const taste = teile.pop();
  return (e.ctrlKey || e.metaKey) === teile.includes("ctrl") && e.shiftKey === teile.includes("shift")
    && e.altKey === teile.includes("alt") && e.key.toLowerCase() === taste;
}

window.addEventListener("keydown", (e) => {
  const strg = e.ctrlKey || e.metaKey;
  if (!strg) return;
  const taste = e.key.toLowerCase();
  const imDialog = document.querySelector("dialog[open]");
  const imEditor = e.target.closest && e.target.closest(".monaco-editor");
  if (!imDialog && !(imEditor && taste === "s")) {  // im Editor speichert Monaco selbst
    const b = BEITRAEGE.befehle.find((x) => x.taste && BEFEHLE[x.id] && tasteTrifft(x.taste, e));
    if (b) { e.preventDefault(); BEFEHLE[b.id](); return; }
  }
  if (taste === "b" && !e.shiftKey && !imDialog) { e.preventDefault(); panelUmschalten(); }
  else if (taste === "j" && !e.shiftKey && !imDialog) { e.preventDefault(); untenUmschalten(); }
  else if (taste === "tab" && !imDialog) { e.preventDefault(); naechsterTab(e.shiftKey ? -1 : 1); }
  else if ((taste === "p" || (taste === "k" && !e.shiftKey)) && typeof paletteOeffnen === "function"
           && !(imDialog && imDialog.id !== "dlg-palette")) {
    e.preventDefault();
    paletteOeffnen(taste === "k" || e.shiftKey ? ">" : "");
  }
});

/* -- Start ----------------------------------------------------------------- */
function schaleStarten() {
  document.querySelectorAll("#aktiv button[data-aktivitaet]").forEach((b) => {
    b.onclick = () => {
      const schale = $("#schale");
      if (S.schale.aktivitaet === b.dataset.aktivitaet && !schale.classList.contains("panel-zu")
          && !schale.classList.contains("panel-offen")) {
        panelUmschalten(false);                // zweiter Klick klappt die Leiste ein
        return;
      }
      aktivitaetWechseln(b.dataset.aktivitaet);
      schale.classList.add("panel-offen");     // schmale Bildschirme: Leiste über dem Inhalt
    };
  });
  document.querySelectorAll(".panel a[data-view]").forEach((a) => {
    a.onclick = (e) => {
      e.preventDefault();
      $("#schale").classList.remove("panel-offen");
      wechsle(a.dataset.view);
    };
  });
  document.querySelectorAll(".panel details[data-abschnitt]").forEach((d) => {
    d.addEventListener("toggle", () => schaleSpeichern());
    // Knöpfe im Abschnittskopf schalten den Abschnitt nicht um.
    $(".abschnitt__aktionen", d).addEventListener("click", (e) => { e.preventDefault(); e.stopPropagation(); });
    abschnittZeichnen(d.dataset.abschnitt);
  });
  griffBinden($("#panel-griff"), (ev) => panelBreiteSetzen(ev.clientX - $("#panel").getBoundingClientRect().left));
  griffBinden($("#unten-griff"), (ev) => untenHoeheSetzen($("#unten").getBoundingClientRect().bottom - ev.clientY));
  const erste = $("#aktiv button[data-aktivitaet]");
  if (erste) aktivitaetWechseln(erste.dataset.aktivitaet);
  document.addEventListener("click", (e) => {      // Handy: Klick daneben schließt die Leiste
    if (!e.target.closest("#panel, #aktiv")) $("#schale").classList.remove("panel-offen");
  });
  document.addEventListener("live-verbunden", statusZeichnen);
  setInterval(statusZeichnen, 5000);
  S.schale.bereit = true;
  document.dispatchEvent(new CustomEvent("schale-bereit"));
}
