<script setup>
import { computed, onMounted, onUnmounted, ref } from "vue";
import { api, wsVerbinden } from "./api.js";
import { layout, store } from "./store.js";
import Graph from "./components/Graph.vue";
import Guide from "./components/Guide.vue";
import Kennzahlen from "./components/Kennzahlen.vue";

const tab = ref("graph");
const navOffen = ref(false);
const fehler = ref("");
const neuName = ref("");
let wsTrennen = null;
let debounceId = null;
let pollId = null;

const laeuft = computed(() => store.run?.status === "running");
const quellenMax = computed(() => {
  const t = store.topics.find((x) => x.name === store.topic);
  return t?.quellen_max ?? 24;
});

async function quellenSetzen(ev) {
  // Regler-Position 1 = ∞ (API-Wert 0); echte Deckel beginnen bei 2,
  // denn 1 Quelle kann nie bestätigen (Konsens braucht 2 unabhängige)
  const pos = parseInt(ev.target.value, 10);
  const wert = pos === 1 ? 0 : pos;
  try {
    await api.einstellen(store.topic, wert);
    await topicsLaden();
  } catch (e) {
    fehler.value = String(e);
  }
}

async function topicsLaden() {
  store.topics = await api.topics();
  if (!store.topic && store.topics.length) store.topic = store.topics[0].name;
}

async function graphLaden() {
  if (!store.topic) return;
  try {
    const g = await api.graph(store.topic);
    layout.value = g.layout;
    store.zaehler = g.zaehler;
    store.gates = g.gates;
    store.run = g.run;
  } catch (e) {
    fehler.value = String(e);
  }
}

function onWs(ev) {
  if (ev.typ === "verbunden") return alles();
  clearTimeout(debounceId);
  debounceId = setTimeout(() => {
    graphLaden();
    topicsLaden();
  }, 250);
}

async function alles() {
  await topicsLaden();
  await graphLaden();
}

async function waehlen(name) {
  store.topic = name;
  navOffen.value = false;
  await graphLaden();
}

async function anlegen() {
  if (!neuName.value.trim()) return;
  try {
    await api.anlegen(neuName.value.trim(), "");
    neuName.value = "";
    await alles();
  } catch (e) {
    fehler.value = String(e);
  }
}

async function aktion(fn) {
  fehler.value = "";
  try {
    await fn(store.topic);
    await graphLaden();
  } catch (e) {
    fehler.value = String(e);
  }
}

async function starten() {
  let budget = null;
  const r = store.run;
  const knapp = r && r.budget_tokens > 0 &&
    (r.verbraucht || 0) >= r.budget_tokens * 0.9;
  if (r?.status === "budget" || (r?.status === "paused" && knapp)) {
    const alt = r.budget_tokens || 2000000;
    const eingabe = window.prompt(
      `Budget ${r.status === "budget" ? "erschöpft" : "fast erschöpft"} ` +
        `(${((r.verbraucht || 0) / 1e6).toFixed(1)}M verbraucht). ` +
        "Neues Token-Budget für diesen Lauf:",
      String(alt + 2000000),
    );
    if (eingabe === null) return;
    budget = parseInt(eingabe, 10) || null;
  }
  await aktion((t) => api.start(t, budget));
}

async function reset() {
  if (!window.confirm(`„${store.topic}" komplett zurücksetzen? ` +
      "Quellen, Atome und Guide werden gelöscht."))
    return;
  await aktion(api.reset);
  await topicsLaden();
}

onMounted(() => {
  alles();
  wsTrennen = wsVerbinden(onWs);
  pollId = setInterval(() => laeuft.value && graphLaden(), 5000);
});
onUnmounted(() => {
  wsTrennen?.();
  clearInterval(pollId);
});
</script>

<template>
  <div class="app">
    <header class="topbar">
      <button class="burger" @click="navOffen = !navOffen">☰</button>
      <nav class="tabs">
        <button :class="{ aktiv: tab === 'graph' }" @click="tab = 'graph'">Pipeline</button>
        <button :class="{ aktiv: tab === 'guide' }" @click="tab = 'guide'">Guide</button>
        <button :class="{ aktiv: tab === 'kennzahlen' }" @click="tab = 'kennzahlen'">
          Kennzahlen
        </button>
      </nav>
      <span class="spacer" />
      <span v-if="store.run" class="runstatus" :data-status="store.run.status">
        {{ store.run.status }}<template v-if="store.run.grund"> · {{ store.run.grund }}</template>
      </span>
      <button v-if="!laeuft" class="primaer" :disabled="!store.topic"
              @click="starten()">Start</button>
      <button v-else @click="aktion(api.pause)">Pause</button>
      <button v-if="!laeuft && store.topic" title="Pipeline auf null zurücksetzen"
              @click="reset()">Reset</button>
      <label v-if="store.topic" class="quellen-regler"
             :title="'Quellen-Deckel — ganz links: unbegrenzt, es stoppt nur die Sättigung'">
        <span>Quellen: <b>{{ quellenMax === 0 ? "∞" : quellenMax }}</b></span>
        <input type="range" min="1" max="48" step="1"
               :value="quellenMax === 0 ? 1 : quellenMax"
               :disabled="laeuft" @change="quellenSetzen($event)" />
      </label>
    </header>

    <aside class="sidebar" :class="{ offen: navOffen }">
      <form @submit.prevent="anlegen">
        <input v-model="neuName" placeholder="Neues Thema…" />
      </form>
      <ul>
        <li v-for="t in store.topics" :key="t.name"
            :class="{ aktiv: t.name === store.topic }" @click="waehlen(t.name)">
          <span>{{ t.titel || t.name }}</span>
          <small>{{ t.status }}</small>
        </li>
      </ul>
    </aside>

    <main>
      <p v-if="fehler" class="fehler" @click="fehler = ''">{{ fehler }}</p>
      <Graph v-if="tab === 'graph'" />
      <Guide v-else-if="tab === 'guide'" />
      <Kennzahlen v-else />
    </main>
  </div>
</template>
