<script setup>
import { ref, computed } from 'vue'

const props = defineProps({
  topics: { type: Array, required: true },
  projects: { type: Array, default: () => [] },
  selectedTopic: { type: String, default: null },
  stats: { type: Object, default: null },
  doneByFormat: { type: Object, default: () => ({}) },
  latestByFormat: { type: Object, default: () => ({}) },
  allGuides: { type: Array, default: () => [] },
  dismissedErrors: { type: Object, default: () => new Set() },
  bausteine: { type: Object, default: () => ({ ready: false, generating: false, progress: null, error: null }) },
  activeBausteine: { type: Array, default: () => [] },
  pinned: { type: Boolean, default: true },
  dark: { type: Boolean, default: false },
  provider: { type: String, default: 'claude' },
  providers: { type: Array, default: () => [] },
})

const emit = defineEmits(['select', 'create', 'formatClick', 'bausteineClick', 'cancelBausteine', 'resetBausteine', 'deleteTopic', 'deleteProject', 'cancelGuide', 'deleteGuide', 'dismissError', 'preview', 'togglePin', 'sidebarLeave', 'toggleDark', 'setProvider'])

function providerAvailable(id) {
  const p = props.providers.find((x) => x.id === id)
  return p ? p.available : true
}

const PROVIDER_LABELS = { claude: 'Claude', minimax: 'MiniMax', lokal: 'Lokal' }

// Tracker oben in der Navigation: Themen gesamt, pro Format erstellt/absolviert
const trackerItems = computed(() => {
  if (!props.stats) return []
  const f = props.stats.formate || {}
  const fmt = (k) => `${f[k]?.absolviert ?? 0}/${f[k]?.erstellt ?? 0}`
  return [
    { label: 'Themen', value: String(props.stats.themen ?? 0), title: 'Themen inkl. Projekte' },
    { label: 'MiniGuides', value: fmt('MiniGuide'), title: 'absolviert/erstellt' },
    { label: 'Guides', value: fmt('Guide'), title: 'absolviert/erstellt' },
    { label: 'FullGuides', value: fmt('FullGuide'), title: 'absolviert/erstellt' },
  ]
})

const formats = [
  { key: 'OnePager', label: 'OnePager' },
  { key: 'MiniGuide', label: 'MiniGuide' },
  { key: 'Guide', label: 'Guide' },
  { key: 'FullGuide', label: 'FullGuide' },
]

const bausteineState = computed(() => {
  if (props.bausteine.generating) return 'generating'
  return props.bausteine.ready ? 'done' : 'none'
})

const activeGenerations = computed(() => {
  const bausteinLines = props.activeBausteine.map(
    (b) => `${b.topic} – Bausteine: ${b.progress || 'Wartend…'}`,
  )
  const guideLines = props.allGuides
    .filter((g) => g.status === 'generating' || g.status === 'queued')
    .map((g) => `${g.topic} – ${g.format}: ${g.progress || 'Wartend…'}`)
  return [...bausteinLines, ...guideLines]
})

// Inline-Bestätigung statt confirm(): erster Klick scharfschalten („Sicher?"),
// zweiter Klick führt aus. Browser-Dialoge können unterdrückt sein (Firefox).
const pendingConfirm = ref(null)
let confirmTimer = null

function armOrRun(key, action) {
  clearTimeout(confirmTimer)
  if (pendingConfirm.value === key) {
    pendingConfirm.value = null
    action()
  } else {
    pendingConfirm.value = key
    confirmTimer = setTimeout(() => { pendingConfirm.value = null }, 3000)
  }
}

function confirmCancelBausteine() {
  armOrRun('bausteine', () => emit('cancelBausteine'))
}

function confirmResetBausteine() {
  armOrRun('bausteine', () => emit('resetBausteine'))
}

function handleBausteinePlay() {
  if (bausteineState.value === 'generating') return
  emit('bausteineClick', { instructions: '' })
}

function guideStatus(format) {
  // Laufende Generierung hat Vorrang — sonst maskiert ein älterer fertiger
  // Guide den Lauf und ▶ würde Duplikate starten.
  const latest = props.latestByFormat[format]
  if (latest && (latest.status === 'generating' || latest.status === 'queued')) return latest.status
  if (props.doneByFormat[format]) return 'done'
  if (!latest || latest.status === 'error') return 'none'
  return latest.status
}

// Schritt-Kugeln der Guide-Pipelines
const GUIDE_STEPS = ['Auswahl', 'Auswahl-Prüfung', 'Gliederung', 'Gliederungs-Prüfung', 'Schreiben', 'Lese-Prüfung']
const ONEPAGER_STEPS = ['Recherche', 'Recherche-Prüfung', 'Bauen', 'Prüfung']

// Kugeln werden wie bei den Bausteinen immer angezeigt:
// fertig = alle grün, laufend = live, abgebrochen = Teilfortschritt, sonst grau
function guideSteps(format) {
  const labels = format === 'OnePager' ? ONEPAGER_STEPS : GUIDE_STEPS
  const st = guideStatus(format)
  if (st === 'generating' || st === 'queued') {
    const step = props.latestByFormat[format]?.step ?? -1
    return labels.map((label, i) => ({
      label,
      state: i < step ? 'done' : i === step ? 'active' : 'pending',
    }))
  }
  if (props.doneByFormat[format]) {
    return labels.map((label) => ({ label, state: 'done' }))
  }
  if (abgebrochen(format)) {
    const step = props.latestByFormat[format]?.step ?? 0
    return labels.map((label, i) => ({ label, state: i < step ? 'done' : 'pending' }))
  }
  return labels.map((label) => ({ label, state: 'pending' }))
}

function errorMsg(format) {
  const latest = props.latestByFormat[format]
  if (latest?.status !== 'error' || props.dismissedErrors.has(latest.id)) return ''
  return latest.error_msg || 'Fehler bei der Generierung'
}

// Abgebrochener Lauf = Teilfortschritt vorhanden: ▶ setzt fort, ✕ löscht den Fortschritt
function abgebrochen(format) {
  const latest = props.latestByFormat[format]
  return latest?.status === 'error' && (latest.error_msg || '').startsWith('Abgebrochen')
}

function handleFormatClick(format) {
  const guide = props.doneByFormat[format]
  if (guide) {
    emit('preview', guide)
  }
}

// Lernschulden-Regel: JE Format max. 5 erstellte, aber nicht absolvierte Guides —
// darüber sind nur Neu-Generierungen bereits erstellter Guides erlaubt.
function offeneGuides(format) {
  const f = props.stats?.formate?.[format]
  return (f?.erstellt ?? 0) - (f?.absolviert ?? 0)
}

function playLock(format) {
  if (format === 'OnePager') return null
  if (!props.bausteine.ready) return 'Erst Bausteine erstellen'
  const offen = offeneGuides(format)
  if (offen >= 5 && !props.doneByFormat[format]) {
    return `Erst ${format}s absolvieren — ${offen} offen (max. 5)`
  }
  return null
}

function handlePlay(format) {
  if (playLock(format)) return
  emit('formatClick', { format, instructions: '' })
}

// Flash-Message-Verhalten: × blendet nur aus, nichts wird gelöscht
function dismissError(format) {
  const latest = props.latestByFormat[format]
  if (latest?.status === 'error') emit('dismissError', latest.id)
}

function handleDelete(format) {
  if (!props.latestByFormat[format]) return
  armOrRun('fmt-' + format, () => {
    // Alle laufenden Generierungen des Formats abbrechen (deckt auch Duplikate ab)
    const running = props.allGuides.filter(
      (g) => g.topic === props.selectedTopic && g.format === format
        && (g.status === 'generating' || g.status === 'queued'),
    )
    if (running.length) {
      for (const g of running) emit('cancelGuide', g.id)
    } else {
      emit('deleteGuide', props.latestByFormat[format].id)
    }
  })
}

const newTopic = ref('')

function submit() {
  const t = newTopic.value.trim()
  if (!t) return
  emit('create', t)
  newTopic.value = ''
}

function confirmDeleteTopic(topic) {
  armOrRun('topic-' + topic, () => emit('deleteTopic', topic))
}

function confirmDeleteProject(name) {
  armOrRun('project-' + name, () => emit('deleteProject', name))
}
</script>

<template>
  <aside class="sidebar" @mouseleave="emit('sidebarLeave')">
    <div class="stats-bar" v-if="trackerItems.length">
      <div class="stat" v-for="item in trackerItems" :key="item.label" :title="item.title">
        <span class="stat-value">{{ item.value }}</span>
        <span class="stat-label">{{ item.label }}</span>
      </div>
    </div>
    <div class="new-topic">
      <button
        class="pin-btn"
        :title="pinned ? 'Sidebar ausblenden' : 'Sidebar fixieren'"
        @click="emit('togglePin')"
      >{{ pinned ? '⇤' : '⇥' }}</button>
      <button
        class="theme-btn"
        :title="dark ? 'Hellmodus' : 'Dunkelmodus'"
        @click="emit('toggleDark')"
      >{{ dark ? '☀' : '🌙' }}</button>
      <input
        v-model="newTopic"
        placeholder="Neues Thema…"
        @keyup.enter="submit"
      />
      <button @click="submit" :disabled="!newTopic.trim()">+</button>
    </div>
    <div class="provider-toggle" v-if="providers.length">
      <button
        v-for="p in providers"
        :key="p.id"
        :class="{ active: p.id === provider }"
        :disabled="!p.available"
        :title="p.available ? '' : 'Nicht konfiguriert (CLI/Key fehlt)'"
        @click="emit('setProvider', p.id)"
      >{{ PROVIDER_LABELS[p.id] || p.id }}</button>
    </div>
    <div class="format-section" v-if="selectedTopic">
      <div class="progress-info" v-if="activeGenerations.length">
        <div v-for="(line, i) in activeGenerations" :key="i">{{ line }}</div>
      </div>
      <div class="format-row bausteine-row ord-bausteine">
        <div class="format-name bausteine-name">
          <span class="format-label">Bausteine</span>
          <span class="step-dots">
            <span
              v-for="s in (bausteine.steps || [])"
              :key="s.label"
              class="step-dot"
              :class="s.state"
              :title="s.state === 'active' ? (bausteine.progress || s.label) : s.label"
            ></span>
          </span>
          <span
            v-if="bausteineState === 'generating'"
            class="format-x"
            :class="{ armed: pendingConfirm === 'bausteine' }"
            title="Aktuellen Schritt abbrechen (Fortschritt bleibt)"
            @click.stop="confirmCancelBausteine"
          >{{ pendingConfirm === 'bausteine' ? 'Sicher?' : '×' }}</span>
          <span
            v-else-if="bausteine.partial"
            class="format-x"
            :class="{ armed: pendingConfirm === 'bausteine' }"
            title="Fortschritt löschen"
            @click.stop="confirmResetBausteine"
          >{{ pendingConfirm === 'bausteine' ? 'Sicher?' : '×' }}</span>
        </div>
        <div class="format-actions">
          <template v-if="bausteineState !== 'generating'">
            <button
              class="action-btn play"
              :title="bausteine.partial ? 'Fortsetzen' : bausteine.ready ? 'Bausteine neu erstellen' : 'Bausteine erstellen'"
              @click="handleBausteinePlay"
            >▶</button>
          </template>
        </div>
      </div>
      <div v-if="bausteine.error" class="format-error ord-bausteine">
        <span class="format-error-text">{{ bausteine.error }}</span>
      </div>
<!-- OnePager (unabhängig von Bausteinen) steht per CSS-order vor der Bausteine-Zeile -->
      <div v-for="f in formats" :key="f.key" :style="{ order: f.key === 'OnePager' ? 1 : 3 }">
        <div :class="['format-row', 'fmt-' + guideStatus(f.key)]">
          <button class="format-name" @click="handleFormatClick(f.key)">
            <span class="format-label">{{ f.label }}</span>
            <span class="step-dots" v-if="guideSteps(f.key).length">
              <span
                v-for="s in guideSteps(f.key)"
                :key="s.label"
                class="step-dot"
                :class="s.state"
                :title="s.state === 'active' ? (latestByFormat[f.key]?.progress || s.label) : s.label"
              ></span>
            </span>
            <span
              v-if="guideStatus(f.key) !== 'none'"
              class="format-x"
              :class="{ armed: pendingConfirm === 'fmt-' + f.key }"
              @click.stop="handleDelete(f.key)"
              :title="guideStatus(f.key) === 'generating' || guideStatus(f.key) === 'queued' ? 'Abbrechen' : 'Löschen'"
            >{{ pendingConfirm === 'fmt-' + f.key ? 'Sicher?' : '×' }}</span>
          </button>
          <div class="format-actions">
            <template v-if="guideStatus(f.key) !== 'generating' && guideStatus(f.key) !== 'queued'">
              <button
                class="action-btn play"
                :title="playLock(f.key) || (abgebrochen(f.key) ? 'Fortsetzen' : 'Generieren')"
                :disabled="!!playLock(f.key)"
                @click="handlePlay(f.key)"
              >▶</button>
            </template>
          </div>
        </div>
        <div v-if="errorMsg(f.key)" class="format-error">
          <span class="format-error-text">{{ errorMsg(f.key) }}</span>
          <button class="format-error-x" title="Ausblenden" @click="dismissError(f.key)">×</button>
        </div>
      </div>
    </div>

    <ul class="topic-list">
      <li
        v-for="t in topics"
        :key="t"
        :class="{ active: t === selectedTopic }"
        @click="emit('select', t)"
      >
        <span>{{ t }}</span>
        <button
          class="delete-topic"
          :class="{ armed: pendingConfirm === 'topic-' + t }"
          @click.stop="confirmDeleteTopic(t)"
          title="Thema und alle Guides löschen"
        >{{ pendingConfirm === 'topic-' + t ? 'Sicher?' : '×' }}</button>
      </li>
      <template v-if="projects.length">
        <li class="projects-divider">Projekte</li>
        <li
          v-for="p in projects"
          :key="'project-' + p"
          :class="{ active: p === selectedTopic, 'project-item': true }"
          @click="emit('select', p)"
        >
          <span>{{ p }}</span>
          <button
            class="delete-topic"
            :class="{ armed: pendingConfirm === 'project-' + p }"
            @click.stop="confirmDeleteProject(p)"
            title="Projekt entfernen (löscht ./projects-Ordner)"
          >{{ pendingConfirm === 'project-' + p ? 'Sicher?' : '×' }}</button>
        </li>
      </template>
    </ul>
  </aside>
</template>

<style scoped>
.sidebar {
  width: 300px;
  min-width: 300px;
  background: var(--panel);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  height: 100vh;
}

.new-topic {
  display: flex;
  gap: 4px;
  padding: 0.75rem;
  border-bottom: 1px solid var(--border);
}

.new-topic input {
  flex: 1;
  min-width: 0;
  padding: 6px 8px;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  font-size: 0.85rem;
  outline: none;
}

.new-topic input:focus {
  border-color: var(--accent);
}

.new-topic button {
  padding: 6px 10px;
  border: none;
  background: var(--accent);
  color: var(--on-accent);
  border-radius: 6px;
  font-size: 1rem;
  font-weight: 700;
  cursor: pointer;
}

.new-topic button:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

.new-topic .pin-btn {
  background: var(--bg);
  color: var(--text-muted);
  border: 1px solid var(--border-strong);
  font-weight: 600;
  padding: 6px 8px;
}

.new-topic .pin-btn:hover {
  background: var(--accent-soft);
  color: var(--accent-hover);
  border-color: var(--accent-border);
}

.new-topic .theme-btn {
  background: var(--bg);
  color: var(--text-muted);
  border: 1px solid var(--border-strong);
  font-weight: 600;
  padding: 6px 8px;
}

.new-topic .theme-btn:hover {
  background: var(--accent-soft);
  color: var(--accent-hover);
  border-color: var(--accent-border);
}

.stats-bar {
  display: flex;
  padding: 0.5rem 0.75rem;
  gap: 4px;
  border-bottom: 1px solid var(--border);
}

.stat {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1px;
  padding: 4px 2px;
  background: var(--panel-soft);
  border: 1px solid var(--border);
  border-radius: 6px;
  cursor: default;
}

.stat-value {
  font-size: 0.8rem;
  font-weight: 700;
  color: var(--text);
}

.stat-label {
  font-size: 0.58rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--text-faint);
  white-space: nowrap;
}

.provider-toggle {
  display: flex;
  gap: 0;
  padding: 0.5rem 0.75rem 0;
}

.provider-toggle button {
  flex: 1;
  padding: 5px 8px;
  font-size: 0.78rem;
  font-weight: 600;
  border: 1px solid var(--border-strong);
  background: var(--bg);
  color: var(--text-muted);
  cursor: pointer;
}

.provider-toggle button:first-child {
  border-radius: 6px 0 0 6px;
}

.provider-toggle button:last-child {
  border-radius: 0 6px 6px 0;
  border-left: none;
}

.provider-toggle button.active {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent);
}

.provider-toggle button:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

.topic-list {
  list-style: none;
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 0.5rem 0;
  border-top: 1px solid var(--border);
}

.topic-list li {
  padding: 0.6rem 1rem;
  cursor: pointer;
  font-size: 0.9rem;
  color: var(--text);
  transition: background 0.15s;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.topic-list li:hover {
  background: var(--accent-soft);
}

.topic-list li.active {
  background: var(--accent-soft);
  color: var(--accent-hover);
  font-weight: 600;
}

.delete-topic {
  display: none;
  background: none;
  border: none;
  color: var(--danger);
  font-size: 1.1rem;
  cursor: pointer;
  padding: 0 2px;
  line-height: 1;
}

.topic-list li:hover .delete-topic {
  display: block;
}

.projects-divider {
  cursor: default;
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-faint);
  font-weight: 700;
  padding: 0.6rem 1rem 0.3rem;
  margin-top: 0.4rem;
  border-top: 1px solid var(--border);
}

.projects-divider:hover {
  background: none;
}

.topic-list li.project-item span::before {
  content: '📁 ';
}

/* Format section */
.bausteine-name {
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: default;
}

.step-dots {
  display: inline-flex;
  gap: 5px;
  flex: 1;
}

.step-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--border-strong);
  flex-shrink: 0;
}

.step-dot.done {
  background: var(--success-border);
}

.step-dot.active {
  background: var(--warning-border);
  animation: dot-pulse 1.2s ease-in-out infinite;
}

@keyframes dot-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}

.action-btn:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}

.format-section {
  flex-shrink: 0;
  max-height: 60vh;
  overflow-y: auto;
  padding: 0.5rem 0;
  /* flex + order: OnePager (order 1) vor Bausteine (order 2) vor den restlichen Formaten (order 3) */
  display: flex;
  flex-direction: column;
}

.ord-bausteine {
  order: 2;
}

.progress-info {
  padding: 0.4rem 0.75rem;
  font-size: 0.75rem;
  color: var(--warning);
  background: var(--warning-soft);
  margin-bottom: 0.25rem;
  animation: pulse 1.5s ease-in-out infinite;
}

.format-row {
  display: flex;
  align-items: center;
  padding: 0.4rem 0.75rem;
  transition: background 0.15s;
}

.format-row:hover {
  background: var(--panel-soft);
}

.format-name {
  flex: 1;
  background: none;
  border: none;
  text-align: left;
  font-size: 0.85rem;
  padding: 4px 8px;
  border-radius: 4px;
  cursor: default;
  color: var(--text-faint);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.format-x {
  display: none;
  color: var(--danger);
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  padding: 0 2px;
}

.format-name:hover .format-x {
  display: inline;
}

.format-x.armed,
.format-error-x.armed,
.delete-topic.armed {
  display: inline-block;
  font-size: 0.7rem;
  font-weight: 700;
  background: var(--danger);
  color: #fff;
  border-radius: 4px;
  padding: 2px 6px;
}

.fmt-done .format-name {
  color: var(--success);
  font-weight: 600;
  cursor: pointer;
  background: var(--success-soft);
  border: 1px solid var(--success-border);
}

.fmt-done .format-name:hover {
  background: var(--success-soft-hover);
}

.fmt-generating .format-name,
.fmt-queued .format-name {
  color: var(--warning);
  background: var(--warning-soft);
  border: 1px solid var(--warning-border);
  animation: pulse 1.5s ease-in-out infinite;
}

.format-error {
  display: flex;
  align-items: flex-start;
  gap: 4px;
  padding: 2px 0.75rem 6px calc(0.75rem + 8px);
  font-size: 0.72rem;
  color: var(--danger);
  line-height: 1.3;
}

.format-error-text {
  flex: 1;
  word-break: break-word;
}

.format-error-x {
  flex: 0 0 auto;
  background: none;
  border: none;
  color: var(--danger);
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
  padding: 0 2px;
  opacity: 0.6;
}

.format-error-x:hover {
  opacity: 1;
}

.format-actions {
  display: flex;
  gap: 2px;
  margin-left: 6px;
}

.action-btn {
  background: none;
  border: 1px solid transparent;
  border-radius: 4px;
  width: 26px;
  height: 26px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  font-size: 0.9rem;
  transition: all 0.15s;
}

.action-btn.play {
  color: var(--success);
}

.action-btn.play:hover {
  background: var(--success-soft);
  border-color: var(--success-border);
}

.action-btn:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}

.action-btn:disabled:hover {
  background: none;
  border-color: transparent;
}

@keyframes pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.65; }
}

</style>
