<script setup>
import { computed, ref, nextTick, onMounted, onUnmounted } from 'vue'
import { marked } from 'marked'
import DOMPurify from 'dompurify'
import { htmlUrl, chatGuide, fetchProgress, setProgress } from '../api.js'

marked.setOptions({ breaks: true, gfm: true })

function renderMarkdown(text) {
  return DOMPurify.sanitize(marked.parse(text || ''))
}

const props = defineProps({
  previewGuide: { type: Object, default: null },
})

const LANDSCAPE_FORMATS = ['OnePager', 'Cheatsheet']
const isLandscape = computed(() => LANDSCAPE_FORMATS.includes(props.previewGuide?.format))

const frameEl = ref(null)

// --- Kapitel-Fortschritt ---
function onFrameLoad(e) {
  const doc = e.target.contentDocument
  if (!doc) return
  injectStyles(doc)
  setupProgress(doc)
  // Klicks im iframe blubbern nicht zum Eltern-document → eigener Listener (same-origin)
  doc.addEventListener('mousedown', onFrameMouseDown)
}

function onFrameMouseDown() {
  if (chatOpen.value) closeChat()
}

function injectStyles(doc) {
  // Ohne viewport-meta rendert das iframe-Dokument mit Desktop-Breite und greift unsere max-width-Query nicht.
  if (!doc.querySelector('meta[name="viewport"]')) {
    const meta = doc.createElement('meta')
    meta.name = 'viewport'
    meta.content = 'width=device-width, initial-scale=1'
    doc.head?.appendChild(meta)
  }

  const style = doc.createElement('style')
  const portrait = !isLandscape.value
    ? `html { background: #f0f1f4; }
       body {
         zoom: 1.15;
         max-width: 1000px;
         margin: 0 auto;
         padding: 2.5rem 3.5rem;
         background: #fff;
         box-shadow: 0 1px 8px rgba(0, 0, 0, 0.08);
       }`
    : ''
  style.textContent = `@media screen {
    ${portrait}
    .ch-toggle {
      display: block;
      width: 100%;
      margin: 2.5rem 0 0.5rem;
      padding: 0.9rem 1rem;
      border: 1.5px dashed #c7ccd6;
      border-radius: 10px;
      background: #f8f9fb;
      color: #4b5563;
      font: 600 0.95rem/1.2 -apple-system, "Segoe UI", Roboto, sans-serif;
      text-align: center;
      cursor: pointer;
      transition: all 0.12s;
    }
    .ch-toggle:hover { border-color: #6366f1; color: #4f46e5; background: #ede9fe; }
    .ch-toggle.is-done {
      border-style: solid;
      border-color: #34d399;
      background: #d1fae5;
      color: #065f46;
    }
    section.chapter.ch-complete > :not(.ch-toggle) { opacity: 0.4; }
  }

  @media screen and (max-width: 700px) {
    html { background: #fff; }
    body {
      zoom: 1 !important;
      max-width: 100% !important;
      padding: 1.25rem 1rem !important;
      box-shadow: none !important;
    }

    /* Cover/Part-Divider: feste mm-Höhen + flex-center fürs Print-A4. Auf Mobile läuft
       zentrierter Inhalt über die Box hinaus und überlappt das nächste Element.
       → als normale Blöcke von oben fließen lassen. */
    .cover, .part-divider {
      height: auto !important;
      min-height: 0 !important;
      justify-content: flex-start !important;
      padding: 2.5rem 1.25rem !important;
      overflow: hidden;
    }
    .cover h1 { font-size: 30pt !important; }
    .cover h1 .light { font-size: 22pt !important; }
    .cover .sub { font-size: 12pt !important; max-width: 100% !important; margin-bottom: 1.5rem !important; }
    .cover .meta-row { flex-wrap: wrap; gap: 0.75rem 1.5rem !important; }
    .cover-deco { font-size: 60pt !important; right: 1rem !important; }

    .part-divider h1 { font-size: 26pt !important; }
    .part-divider .part-desc { max-width: 100% !important; }

    .chapter-head h1 { font-size: 22pt !important; }

    /* Print schneidet Code hart ab (overflow: hidden) → auf Mobile umbrechen + scrollbar */
    pre {
      white-space: pre-wrap !important;
      word-break: break-word;
      overflow-x: auto !important;
    }

    /* Blocksatz erzeugt riesige Wortlücken in schmalen Spalten */
    p { text-align: left !important; }

    /* Breite Tabellen horizontal scrollbar statt überlaufend */
    table { display: block; width: 100%; overflow-x: auto; }
  }`
  doc.head?.appendChild(style)
}

async function setupProgress(doc) {
  const guideId = props.previewGuide?.id
  const chapters = Array.from(doc.querySelectorAll('section.chapter'))
  if (!guideId || !chapters.length) return

  let done = new Set()
  try {
    const res = await fetchProgress(guideId)
    done = new Set(res.chapters || [])
  } catch { /* offline → leer */ }

  chapters.forEach((section, i) => {
    if (section.querySelector(':scope > .ch-toggle')) return // Guard gegen Doppel-Inject
    const numEl = section.querySelector('.chapter-num')
    const key = (numEl?.textContent.match(/\d+/)?.[0]) || String(i + 1)

    const toggle = doc.createElement('div')
    toggle.className = 'ch-toggle'
    const apply = (isDone) => {
      toggle.classList.toggle('is-done', isDone)
      section.classList.toggle('ch-complete', isDone)
      toggle.textContent = isDone ? '✓ Erledigt – rückgängig' : 'Kapitel als erledigt markieren'
    }
    apply(done.has(key))

    toggle.addEventListener('click', async () => {
      const newState = !section.classList.contains('ch-complete')
      apply(newState)
      try {
        await setProgress(guideId, key, newState)
      } catch {
        apply(!newState) // Rollback bei Fehler
      }
    })
    section.appendChild(toggle)
  })

  // Zum ersten noch offenen Kapitel springen — aber nur, wenn davor schon was erledigt ist.
  // Frischer Guide (nichts erledigt) bleibt oben beim Cover.
  const firstOpen = chapters.find((s) => !s.classList.contains('ch-complete'))
  if (firstOpen && firstOpen !== chapters[0]) {
    firstOpen.scrollIntoView({ block: 'start' })
  }
}

// --- Chat ---
const chatOpen = ref(false)
const messages = ref([])
const input = ref('')
const loading = ref(false)
const messagesEl = ref(null)
const inputEl = ref(null)
const panelEl = ref(null)

function openChat() {
  chatOpen.value = true
  nextTick(() => inputEl.value?.focus())
}

function closeChat() {
  chatOpen.value = false
  messages.value = []
  input.value = ''
}

// Klicks außerhalb des iframes (Sidebar, Ränder) — mousedown vermeidet die Open/Close-Race beim FAB
function onDocMouseDown(e) {
  if (!chatOpen.value) return
  if (panelEl.value && panelEl.value.contains(e.target)) return
  closeChat()
}

// Enter öffnet den Chat (wenn zu, nicht in Eingabefeld); ESC schließt ihn
function onDocKeyDown(e) {
  if (e.key === 'Escape' && chatOpen.value) {
    e.preventDefault()
    closeChat()
    return
  }
  if (e.key !== 'Enter' || chatOpen.value || !props.previewGuide) return
  const tag = document.activeElement?.tagName
  if (tag === 'INPUT' || tag === 'TEXTAREA') return
  e.preventDefault()
  openChat()
}

onMounted(() => {
  document.addEventListener('mousedown', onDocMouseDown, true)
  document.addEventListener('keydown', onDocKeyDown)
})
onUnmounted(() => {
  document.removeEventListener('mousedown', onDocMouseDown, true)
  document.removeEventListener('keydown', onDocKeyDown)
})

function extractContext() {
  try {
    const doc = frameEl.value?.contentDocument
    if (!doc) return { section: '', outline: '' }
    const headings = Array.from(doc.querySelectorAll('h1, h2, h3'))
    if (!headings.length) return { section: '', outline: '' }

    const outline = headings.map((h) => h.innerText.trim()).filter(Boolean).join('\n')

    // Aktuelle Überschrift = letzte, die oben im sichtbaren Bereich oder darüber liegt
    let current = headings[0]
    for (const h of headings) {
      if (h.getBoundingClientRect().top <= 100) current = h
      else break
    }
    const level = Number(current.tagName[1])
    const idx = headings.indexOf(current)
    let end = null
    for (let i = idx + 1; i < headings.length; i++) {
      if (Number(headings[i].tagName[1]) <= level) { end = headings[i]; break }
    }
    const range = doc.createRange()
    range.setStartBefore(current)
    if (end) range.setEndBefore(end)
    else range.setEndAfter(doc.body.lastElementChild || doc.body)
    const section = range.toString().trim().slice(0, 18000)
    return { section, outline: outline.slice(0, 7000) }
  } catch {
    return { section: '', outline: '' }
  }
}

async function scrollToBottom() {
  await nextTick()
  if (messagesEl.value) messagesEl.value.scrollTop = messagesEl.value.scrollHeight
}

async function send() {
  const text = input.value.trim()
  if (!text || loading.value || !props.previewGuide) return
  messages.value.push({ role: 'user', content: text })
  input.value = ''
  loading.value = true
  scrollToBottom()
  try {
    const { section, outline } = extractContext()
    const res = await chatGuide(props.previewGuide.id, {
      section,
      outline,
      messages: messages.value,
    })
    messages.value.push({ role: 'assistant', content: res.reply || '…' })
  } catch {
    messages.value.push({ role: 'assistant', content: 'Fehler bei der Anfrage.' })
  } finally {
    loading.value = false
    scrollToBottom()
    nextTick(() => inputEl.value?.focus())
  }
}
</script>

<template>
  <div class="detail">
    <div class="preview" :class="{ landscape: isLandscape }" v-if="previewGuide">
      <iframe ref="frameEl" :src="htmlUrl(previewGuide.id)" class="preview-frame" :class="{ landscape: isLandscape }" title="Guide-Vorschau" @load="onFrameLoad"></iframe>
    </div>

    <div class="empty-preview" v-else>
      <p>Guide-Format anklicken um zu generieren oder Vorschau zu öffnen.</p>
    </div>

    <button v-if="previewGuide && !chatOpen" class="chat-fab" title="Fragen zum Guide" @click="openChat">💬</button>

    <div v-if="previewGuide && chatOpen" ref="panelEl" class="chat-panel">
      <header class="chat-header">
        <span>Fragen zum Guide</span>
        <button class="chat-close" title="Chat beenden" @click="closeChat">×</button>
      </header>
      <div ref="messagesEl" class="chat-messages">
        <p v-if="!messages.length" class="chat-hint">Stell eine Frage zum aktuellen Abschnitt.</p>
        <template v-for="(m, i) in messages" :key="i">
          <div v-if="m.role === 'assistant'" class="chat-msg assistant markdown" v-html="renderMarkdown(m.content)"></div>
          <div v-else class="chat-msg user">{{ m.content }}</div>
        </template>
        <div v-if="loading" class="chat-msg assistant chat-typing">Denkt…</div>
      </div>
      <div class="chat-input">
        <textarea
          ref="inputEl"
          v-model="input"
          placeholder="Frage stellen…"
          @keydown.enter.exact.prevent="send"
        ></textarea>
        <button :disabled="!input.trim() || loading" @click="send">➤</button>
      </div>
    </div>
  </div>
</template>

<style scoped>
.detail {
  flex: 1;
  height: 100vh;
}

.preview {
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  background: #f0f1f4;
}

.preview.landscape {
  padding: 2rem;
}

.preview-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0.4rem 1rem;
  background: #f8f9fb;
  border-bottom: 1px solid #e2e5e9;
  font-size: 0.85rem;
  font-weight: 600;
  color: #5a6470;
  flex-shrink: 0;
}

.preview-actions {
  display: flex;
  gap: 0.75rem;
}

.preview-link {
  color: #6366f1;
  text-decoration: none;
  font-size: 0.8rem;
}

.preview-link:hover {
  text-decoration: underline;
}

.preview-frame {
  width: 100%;
  flex: 1;
  border: none;
  background: #fff;
}

.preview-frame.landscape {
  max-width: 1180px;
  box-shadow: 0 1px 8px rgba(0, 0, 0, 0.08);
}

.empty-preview {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  color: #5a6470;
}

.chat-fab {
  position: fixed;
  right: 1.5rem;
  bottom: 1.5rem;
  width: 52px;
  height: 52px;
  border: none;
  border-radius: 50%;
  background: #6366f1;
  color: #fff;
  font-size: 1.4rem;
  cursor: pointer;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.25);
  z-index: 20;
}

.chat-fab:hover {
  background: #4f46e5;
}

.chat-panel {
  position: fixed;
  right: 1.5rem;
  bottom: 1.5rem;
  width: 360px;
  height: 500px;
  max-height: calc(100vh - 3rem);
  display: flex;
  flex-direction: column;
  background: #fff;
  border: 1px solid #e2e5e9;
  border-radius: 12px;
  box-shadow: 0 4px 24px rgba(0, 0, 0, 0.18);
  z-index: 20;
  overflow: hidden;
}

.chat-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.6rem 0.9rem;
  background: #6366f1;
  color: #fff;
  font-weight: 600;
  font-size: 0.9rem;
}

.chat-close {
  border: none;
  background: none;
  color: #fff;
  font-size: 1.4rem;
  line-height: 1;
  cursor: pointer;
  padding: 0 4px;
}

.chat-messages {
  flex: 1;
  overflow-y: auto;
  padding: 0.9rem;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.chat-hint {
  color: #9aa3af;
  font-size: 0.82rem;
  text-align: center;
  margin-top: 1rem;
}

.chat-msg {
  max-width: 85%;
  padding: 7px 11px;
  border-radius: 12px;
  font-size: 0.85rem;
  line-height: 1.4;
  white-space: pre-wrap;
  word-break: break-word;
}

.chat-msg.user {
  align-self: flex-end;
  background: #6366f1;
  color: #fff;
  border-bottom-right-radius: 3px;
}

.chat-msg.assistant {
  align-self: flex-start;
  background: #f1f3f7;
  color: #1a1a1a;
  border-bottom-left-radius: 3px;
}

.chat-typing {
  color: #9aa3af;
  font-style: italic;
}

.chat-msg.markdown :deep(p) {
  margin: 0 0 0.5em;
}

.chat-msg.markdown :deep(p:last-child) {
  margin-bottom: 0;
}

.chat-msg.markdown :deep(ul),
.chat-msg.markdown :deep(ol) {
  margin: 0.3em 0;
  padding-left: 1.2em;
}

.chat-msg.markdown :deep(li) {
  margin: 0.15em 0;
}

.chat-msg.markdown :deep(code) {
  background: #e4e7ee;
  padding: 1px 4px;
  border-radius: 4px;
  font-family: "SF Mono", Consolas, monospace;
  font-size: 0.8em;
}

.chat-msg.markdown :deep(pre) {
  background: #1e2330;
  color: #e6e8ee;
  padding: 8px 10px;
  border-radius: 8px;
  overflow-x: auto;
  margin: 0.5em 0;
}

.chat-msg.markdown :deep(pre code) {
  background: none;
  padding: 0;
  color: inherit;
  font-size: 0.78em;
}

.chat-msg.markdown :deep(h1),
.chat-msg.markdown :deep(h2),
.chat-msg.markdown :deep(h3) {
  font-size: 0.95em;
  margin: 0.4em 0 0.2em;
}

.chat-msg.markdown :deep(a) {
  color: #4f46e5;
}

.chat-msg.markdown :deep(table) {
  border-collapse: collapse;
  font-size: 0.95em;
}

.chat-msg.markdown :deep(th),
.chat-msg.markdown :deep(td) {
  border: 1px solid #d8dde3;
  padding: 2px 6px;
}

.chat-input {
  display: flex;
  gap: 6px;
  padding: 0.6rem;
  border-top: 1px solid #e2e5e9;
}

.chat-input textarea {
  flex: 1;
  resize: none;
  height: 38px;
  padding: 8px 10px;
  border: 1px solid #d8dde3;
  border-radius: 8px;
  font-size: 0.85rem;
  font-family: inherit;
  outline: none;
}

.chat-input textarea:focus {
  border-color: #6366f1;
}

.chat-input button {
  width: 38px;
  border: none;
  border-radius: 8px;
  background: #6366f1;
  color: #fff;
  font-size: 1rem;
  cursor: pointer;
}

.chat-input button:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
</style>
