<script setup>
import { ref, computed, watch, onUnmounted } from 'vue'
import { fetchGuideBoard, fetchRuns, repairGuideBoard, runQa } from '../api.js'
import { usePolling } from '../composables/usePolling.js'
import { useConfirm } from '../composables/useConfirm.js'
import { fmtRuntime, fmtTokens } from '../format.js'
import KanbanBoard from './KanbanBoard.vue'
import ProgressBar from './ProgressBar.vue'

const props = defineProps({
  topic: { type: String, required: true },
  format: { type: String, default: 'Guide' },
  refresh: { type: Number, default: 0 },  // Eltern-Signal: QA/Repair schrieben einen Guide-Report
  auto: { type: Boolean, default: true },
})
const emit = defineEmits(['cancelGuide', 'startGuide', 'preview', 'removeFormat', 'setAuto'])

const board = ref(null)
const pollError = ref(null)

async function poll() {
  try {
    board.value = await fetchGuideBoard(props.topic, props.format)
    pollError.value = null
  } catch (e) {
    if (e.status === 404) board.value = null
    else pollError.value = e.message
  }
}
const { start: startPoll } = usePolling(poll, () => !!board.value?.generating, 1200)

watch(() => props.topic, () => { board.value = null; poll() }, { immediate: true })
watch(() => props.refresh, () => poll())
watch(() => board.value?.generating, (g) => { if (g) startPoll() })

const generating = computed(() => !!board.value?.generating)
const columns = computed(() => board.value?.columns || [])
const total = computed(() => columns.value.reduce((n, c) => n + c.total, 0))
const done = computed(() => columns.value.find((c) => c.key === 'done')?.total || 0)
const progressValue = computed(() => (total.value ? done.value / total.value : 0))
// QA-Badge nur wenn es ein Board gibt — sonst zeigt ein verwaister Report eine alte Note.
const qaNote = computed(() => (total.value ? board.value?.qa_guide : null))

// Laufzeit + Tokens aus /api/runs (deckt auch Guide-Läufe ab — beide setzen run_id)
const run = ref(null)
const now = ref(Date.now())
let clock = null
async function loadRun() {
  try {
    const { runs } = await fetchRuns(props.topic, 1)
    run.value = runs[0] || null
  } catch { run.value = null }
}
const { start: startRunPoll } = usePolling(loadRun, () => generating.value, 5000)
const runLaufzeit = computed(() => {
  if (!run.value?.start) return null
  const start = Date.parse(run.value.start)
  const ende = run.value.aktiv ? now.value : Date.parse(run.value.ende || run.value.start)
  return fmtRuntime((ende - start) / 1000)
})
const runTokens = computed(() => {
  const t = run.value?.tokens
  return t ? fmtTokens((t.input || 0) + (t.output || 0)) : null
})
watch(() => generating.value, (g) => {
  if (g) { startRunPoll(); if (!clock) clock = setInterval(() => { now.value = Date.now() }, 1000) }
  else { loadRun(); if (clock) { clearInterval(clock); clock = null } }
}, { immediate: true })
watch(() => props.topic, () => { run.value = null; loadRun() })
onUnmounted(() => { if (clock) clearInterval(clock) })

const { isArmed, armOrRun } = useConfirm()  // 2-Klick-Bestätigung

const qaBusy = ref(false)
async function runQaClick() {
  if (qaBusy.value) return
  qaBusy.value = true
  try { await runQa(props.topic) }
  finally { qaBusy.value = false; poll() }
}

function removeClick() {
  emit('removeFormat', props.format)
  board.value = null       // optimistisch: Karten + QA-Badge sofort weg, poll bestätigt
  setTimeout(poll, 800)
}

const repairBusy = ref(false)
const repairInfo = ref('')
// Wartet, bis die Guide-Regenerierung der offenen Karten fertig ist (für den Auto-Loop).
function warteBisFertig(timeoutMs = 300000) {
  return new Promise((resolve) => {
    const t0 = Date.now()
    const iv = setInterval(async () => {
      await poll()
      if (!board.value?.generating || Date.now() - t0 > timeoutMs) { clearInterval(iv); resolve() }
    }, 2000)
  })
}
// Auto an → Loop: Befunde beheben → regenerieren → QA, bis 100 % / Stillstand / 10×.
// Auto aus → genau ein Durchlauf (nur anstoßen).
async function repairClick() {
  if (repairBusy.value) return
  const max = props.auto ? 10 : 1
  repairBusy.value = true
  repairInfo.value = ''
  let prev = null
  try {
    for (let i = 0; i < max; i++) {
      const r = await repairGuideBoard(props.topic, props.format)
      if (!(r.betroffen || []).length) {
        repairInfo.value = i === 0 ? 'keine Befunde im letzten QA-Report' : `fertig nach ${i} Runde(n)`
        break
      }
      repairInfo.value = `Runde ${i + 1}: ${r.betroffen.length} Abschnitt(e) → Prüfen…`
      startPoll()
      if (max === 1) break              // ohne Auto: nur anstoßen, nicht auf Fertigstellung warten
      await warteBisFertig()            // Regenerierung abwarten
      await runQa(props.topic)          // neue Guide-QA messen
      await poll()
      const note = board.value?.qa_guide
      if (note == null || note >= 10) { repairInfo.value = `100 % nach ${i + 1} Runde(n)`; break }
      if (prev != null && note <= prev) { repairInfo.value = `Stillstand bei ${Math.round(note * 10)} %`; break }
      prev = note
    }
  } catch (e) {
    repairInfo.value = String(e.message || e)
  } finally {
    repairBusy.value = false
    poll()
  }
}
</script>

<template>
  <section class="gb-board">
    <div class="gen-board-label">
      Guide · {{ format }}
      <span v-if="qaNote != null" class="qa-note" :class="qaNote >= 10 ? 'ok' : 'bad'">QA {{ Math.round(qaNote * 10) }} %</span>
      <label class="auto-box" title="Nach der QA automatisch „Befunde beheben“, bis 100 % (max 10×)">
        <input type="checkbox" :checked="auto" @change="emit('setAuto', $event.target.checked)"> Auto
      </label>
      <span v-if="total" class="gb-count">{{ done }}/{{ total }} Karten</span>
      <span v-if="runLaufzeit" class="gb-count">⏱ {{ runLaufzeit }}<template v-if="runTokens"> · {{ runTokens }} Tokens</template></span>
      <div v-if="board?.progress && generating" class="gen-progress"><span class="gen-progress-dot"></span>{{ board.progress }}</div>
      <div v-if="board?.error" class="gb-error">{{ board.error }}</div>
      <div v-if="pollError" class="gb-error">Board nicht erreichbar: {{ pollError }}</div>
    </div>

    <div v-if="generating" class="gen-bar">
      <button class="gen-act danger" @click="emit('cancelGuide', board?.guide_id)">Abbrechen</button>
    </div>
    <div v-else class="gen-bar">
      <button class="gen-act" :disabled="qaBusy" @click="runQaClick">{{ qaBusy ? 'QA läuft…' : 'QA' }}</button>
      <button v-if="total && qaNote != null && qaNote < 10" class="gen-act" :disabled="repairBusy" @click="repairClick">{{ repairBusy ? 'Repariert…' : 'Befunde beheben' }}</button>
      <span v-if="repairInfo" class="repair-info">{{ repairInfo }}</span>
      <button class="gen-act play" @click="emit('startGuide', { format }); startPoll()">{{ total && done < total ? 'Fortsetzen' : total ? 'Neu generieren' : 'Generieren' }}</button>
      <button v-if="done === total && total" class="gen-act" @click="emit('preview')">Guide öffnen</button>
      <button v-if="total" class="gen-act danger" :class="{ armed: isArmed('delete') }" @click="armOrRun('delete', removeClick)">{{ isArmed('delete') ? 'Sicher?' : 'Entfernen' }}</button>
    </div>

    <ProgressBar v-if="total" :value="progressValue"
                 :label="`${done}/${total} Karten fertig · ${Math.round(progressValue * 100)} %`" />

    <KanbanBoard :columns="columns" :agents="board?.agents || []" :generating="generating" />

    <div v-if="!total && !generating" class="gb-empty">Noch kein Board — «Generieren» erzeugt eine Karte je Baustein und schiebt sie live durch die Spalten.</div>
  </section>
</template>

<style scoped>
.gb-board { padding: 0.85rem 0 0; }
.gen-board-label {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font-size: 0.64rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-faint);
  margin: 0.2rem 0 0.3rem;
}
.gen-bar { display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap; margin: 0.1rem 0 0.4rem; }
.gb-count { color: var(--text-muted); font-size: 0.82rem; text-transform: none; letter-spacing: 0; font-weight: 400; }
.qa-note {
  font-size: 0.78rem;
  font-weight: 600;
  padding: 0.1rem 0.5rem;
  border-radius: 999px;
  text-transform: none;
  letter-spacing: 0;
}
.qa-note.ok { background: color-mix(in srgb, #22c55e 18%, transparent); color: #16a34a; }
.qa-note.bad { background: color-mix(in srgb, #ef4444 18%, transparent); color: #dc2626; }
.auto-box {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  font-size: 0.68rem;
  font-weight: 600;
  color: var(--text-muted);
  text-transform: none;
  letter-spacing: 0;
  cursor: pointer;
}
.auto-box input { cursor: pointer; margin: 0; }
.gen-progress {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.84rem;
  color: var(--accent);
  font-weight: 600;
  text-transform: none;
  letter-spacing: 0;
}
.gen-progress-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent);
  animation: pulse-soft 1.2s ease-in-out infinite;
}
.gb-error { color: var(--danger); font-size: 0.82rem; text-transform: none; letter-spacing: 0; font-weight: 400; }
.gb-empty { color: var(--text-faint); font-size: 0.85rem; padding: 1rem 0; }
.repair-info { font-size: 0.78rem; color: var(--text-muted); }

.gen-act {
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  background: var(--panel);
  color: var(--text);
  font-size: 0.8rem;
  padding: 0.3rem 0.7rem;
  cursor: pointer;
  font-weight: 600;
}
.gen-act:hover { border-color: var(--accent); }
.gen-act:disabled { opacity: 0.55; cursor: default; }
.gen-act.play { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.gen-act.play:hover { background: var(--accent-hover); }
.gen-act.danger { color: var(--danger); border-color: var(--danger); background: transparent; }
.gen-act.danger.armed { background: var(--danger); color: #fff; }
</style>
