<!--
  全屏报告阅读器 — 交付物文档的沉浸式阅读视图。
  参考 D:\population-decline\report.html 的 TOC + 进度条设计。
-->
<template>
  <a-drawer
    :open="open"
    placement="right"
    :width="'100%'"
    :closable="false"
    :body-style="{ padding: 0 }"
    class="report-reader-drawer"
    @close="emit('close')"
  >
    <!-- Progress bar -->
    <div class="rdr-progress" :style="{ width: progressWidth + '%' }" />

    <!-- Top bar -->
    <nav class="rdr-topbar">
      <a class="rdr-topbar__back" @click="emit('close')">
        <LeftOutlined /> 返回
      </a>
      <span class="rdr-topbar__title">{{ docTitle }}</span>
      <div class="rdr-topbar__actions">
        <a-button size="small" @click="tocVisible = !tocVisible" class="rdr-topbar__toc-btn">
          目录
        </a-button>
      </div>
    </nav>

    <!-- Mobile TOC overlay -->
    <div v-if="tocVisible" class="rdr-toc-overlay" @click="tocVisible = false" />

    <!-- Layout -->
    <div class="rdr-layout">
      <!-- TOC sidebar -->
      <aside class="rdr-toc" :class="{ 'rdr-toc--open': tocVisible }">
        <h4 class="rdr-toc__heading">目录导航</h4>
        <ul class="rdr-toc__list">
          <li v-for="item in tocItems" :key="item.id">
            <a
              :href="'#' + item.id"
              :class="['rdr-toc__link', item.cls, { active: activeId === item.id }]"
              @click.prevent="scrollToHeading(item.id)"
            >
              {{ item.text }}
            </a>
          </li>
        </ul>
      </aside>

      <!-- Article content -->
      <main class="rdr-article" ref="articleRef">
        <div class="md-body" ref="contentRef" v-html="renderedHtml" />
      </main>
    </div>

    <!-- Floating action buttons -->
    <div class="rdr-fab-group">
      <a-tooltip title="复制内容" placement="left">
        <a-button shape="circle" class="rdr-fab" @click="handleCopy">
          <template #icon><CopyOutlined /></template>
        </a-button>
      </a-tooltip>
      <a-tooltip title="下载 Markdown" placement="left">
        <a-button shape="circle" class="rdr-fab" @click="handleDownloadMd">
          <template #icon><DownloadOutlined /></template>
        </a-button>
      </a-tooltip>
      <a-tooltip title="导出 Word" placement="left">
        <a-button shape="circle" class="rdr-fab" :loading="exporting" @click="handleExportWord">
          <template #icon><FileWordOutlined /></template>
        </a-button>
      </a-tooltip>
      <a-tooltip title="回到顶部" placement="left">
        <a-button shape="circle" class="rdr-fab" :class="{ show: scrollY > 400 }" @click="scrollToTop">
          <template #icon><UpOutlined /></template>
        </a-button>
      </a-tooltip>
    </div>
  </a-drawer>
</template>

<script setup lang="ts">
import { ref, computed, watch, onMounted, onBeforeUnmount, nextTick } from 'vue'
import { LeftOutlined, UpOutlined, FileWordOutlined, CopyOutlined, DownloadOutlined } from '@ant-design/icons-vue'
import { message } from 'ant-design-vue'
import { createMarkdownIt } from '@/utils/markdown'

const props = defineProps<{
  open: boolean
  content: string
  title?: string
}>()

const emit = defineEmits<{
  (e: 'close'): void
}>()

const md = createMarkdownIt({ referenceLinks: true })

const contentRef = ref<HTMLElement | null>(null)
const articleRef = ref<HTMLElement | null>(null)
const tocVisible = ref(false)
const scrollY = ref(0)
const progressWidth = ref(0)
const activeId = ref('')

interface TocItem {
  id: string
  text: string
  cls: string
}
const tocItems = ref<TocItem[]>([])

const renderedHtml = computed(() => {
  if (!props.content) return ''
  let html = md.render(props.content)
  // Wrap tables for horizontal scroll
  html = html.replace(/<table>/g, '<div class="table-wrap"><table>').replace(/<\/table>/g, '</table></div>')
  return html
})

const docTitle = computed(() => {
  if (props.title) return props.title
  // Extract from first h1 in content
  const match = props.content?.match(/^#\s+(.+)$/m)
  return match ? match[1] : '研究报告'
})

function buildToc() {
  if (!contentRef.value) return
  const headings = contentRef.value.querySelectorAll('h2, h3, h4')
  const items: TocItem[] = []
  headings.forEach((h, idx) => {
    const level = parseInt(h.tagName[1])
    const cls = level === 2 ? '' : level === 3 ? 'rdr-toc__link--t2' : 'rdr-toc__link--t3'
    const id = h.id || `sec-${idx}`
    h.id = id
    let text = h.textContent || ''
    if (text.length > 30) text = text.slice(0, 28) + '...'
    items.push({ id, text, cls })
  })
  tocItems.value = items
}

function onScroll() {
  if (!contentRef.value) return
  const drawer = contentRef.value.closest('.ant-drawer-body')
  if (!drawer) return
  const st = drawer.scrollTop
  const docH = drawer.scrollHeight - drawer.clientHeight
  scrollY.value = st
  progressWidth.value = docH > 0 ? (st / docH) * 100 : 0

  // Find active heading
  let found = ''
  const headings = contentRef.value.querySelectorAll('h2, h3')
  for (let i = headings.length - 1; i >= 0; i--) {
    if ((headings[i] as HTMLElement).getBoundingClientRect().top <= 100) {
      found = headings[i].id
      break
    }
  }
  activeId.value = found
}

function scrollToHeading(id: string) {
  const el = document.getElementById(id)
  if (el) {
    el.scrollIntoView({ behavior: 'smooth', block: 'start' })
    tocVisible.value = false
  }
}

function scrollToTop() {
  const drawer = contentRef.value?.closest('.ant-drawer-body')
  if (drawer) drawer.scrollTo({ top: 0, behavior: 'smooth' })
}

function handlePrint() {
  window.print()
}

function handleCopy() {
  if (!props.content) return
  navigator.clipboard.writeText(props.content).then(
    () => message.success('已复制到剪贴板'),
    () => message.error('复制失败'),
  )
}

function handleDownloadMd() {
  if (!props.content) return
  const blob = new Blob([props.content], { type: 'text/markdown;charset=utf-8' })
  const url = URL.createObjectURL(blob)
  const a = document.createElement('a')
  a.href = url
  a.download = (docTitle.value || '文档').replace(/[<>:"/\\|?*]/g, '_') + '.md'
  a.click()
  URL.revokeObjectURL(url)
}

const exporting = ref(false)

async function handleExportWord() {
  if (!contentRef.value) return
  exporting.value = true
  try {
    const { asBlob } = await import('html-docx-js-typescript')
    const { saveAs } = await import('file-saver')

    // Build a standalone HTML document with inline styles for Word
    const htmlContent = `
      <!DOCTYPE html>
      <html>
      <head><meta charset="utf-8"><style>
        body { font-family: "Microsoft YaHei", "SimSun", sans-serif; font-size: 14px; line-height: 1.8; color: #1a1a18; padding: 40px; }
        h1 { font-size: 24px; font-weight: bold; margin: 0 0 16px; }
        h2 { font-size: 20px; font-weight: bold; margin: 32px 0 12px; padding-bottom: 8px; border-bottom: 1px solid #ccc; }
        h3 { font-size: 17px; font-weight: bold; margin: 24px 0 8px; }
        h4 { font-size: 15px; font-weight: bold; margin: 16px 0 8px; }
        p { margin: 0 0 12px; }
        ul, ol { margin: 0 0 12px; padding-left: 24px; }
        li { margin: 4px 0; }
        blockquote { border-left: 3px solid #2C5F8A; background: #f0f6fc; padding: 8px 16px; margin: 12px 0; }
        table { width: 100%; border-collapse: collapse; margin: 12px 0; }
        th { background: #f3f2ee; padding: 8px 12px; border: 1px solid #ccc; font-weight: bold; text-align: center; }
        td { padding: 6px 12px; border: 1px solid #ccc; text-align: center; }
        code { font-family: Consolas, monospace; background: #f3f2ee; padding: 1px 4px; }
        pre { background: #f3f2ee; padding: 12px; overflow-x: auto; }
        a { color: #2C5F8A; }
      </style></head>
      <body>${contentRef.value.innerHTML}</body>
      </html>
    `

    const blob = await asBlob(htmlContent) as Blob
    const fileName = (docTitle.value || '文档').replace(/[<>:"/\\|?*]/g, '_') + '.docx'
    saveAs(blob, fileName)
    message.success('已导出 Word 文档')
  } catch (err: any) {
    console.error('Export Word failed:', err)
    message.error('导出失败')
  } finally {
    exporting.value = false
  }
}

let scrollContainer: Element | null = null

watch(() => props.open, async (val) => {
  if (val) {
    await nextTick()
    buildToc()
    // Attach scroll listener to drawer body
    scrollContainer = contentRef.value?.closest('.ant-drawer-body') || null
    if (scrollContainer) {
      scrollContainer.addEventListener('scroll', onScroll, { passive: true })
      onScroll()
    }
    // External links open in new tab
    contentRef.value?.querySelectorAll('a[href^="http"]').forEach((a) => {
      ;(a as HTMLAnchorElement).target = '_blank'
      ;(a as HTMLAnchorElement).rel = 'noopener'
    })
  } else {
    if (scrollContainer) {
      scrollContainer.removeEventListener('scroll', onScroll)
      scrollContainer = null
    }
  }
})

onBeforeUnmount(() => {
  if (scrollContainer) {
    scrollContainer.removeEventListener('scroll', onScroll)
  }
})
</script>

<style lang="less">
/* Force full-screen drawer */
.report-reader-drawer .ant-drawer-content-wrapper {
  width: 100% !important;
}

/* Progress bar */
.rdr-progress {
  position: fixed;
  top: 0;
  left: 0;
  height: 2px;
  background: #2C5F8A;
  z-index: 1001;
  transition: width 0.1s;
}

/* Top bar */
.rdr-topbar {
  position: sticky;
  top: 0;
  z-index: 100;
  background: rgba(250, 250, 247, 0.92);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid #e5e4df;
  padding: 0 24px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 52px;

  &__back {
    color: #2C5F8A;
    cursor: pointer;
    font-size: 14px;
    display: flex;
    align-items: center;
    gap: 6px;
    &:hover { opacity: 0.7; }
  }

  &__title {
    font-size: 14px;
    color: #6b6b66;
    font-weight: 500;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 50%;
  }

  &__actions {
    display: flex;
    gap: 10px;
    align-items: center;
  }

  &__toc-btn {
    display: none;
  }
}

/* Layout */
.rdr-layout {
  display: flex;
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 24px;
  gap: 32px;
}

/* TOC sidebar */
.rdr-toc {
  width: 260px;
  flex-shrink: 0;
  position: sticky;
  top: 68px;
  align-self: flex-start;
  max-height: calc(100vh - 84px);
  overflow-y: auto;
  padding: 20px 0;
  scrollbar-width: thin;

  &__heading {
    font-size: 13px;
    color: #9e9e98;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    margin-bottom: 12px;
    padding-left: 12px;
  }

  &__list {
    list-style: none;
    padding: 0;
    margin: 0;
  }

  &__link {
    display: block;
    font-size: 13px;
    color: #6b6b66;
    text-decoration: none;
    padding: 4px 12px;
    border-left: 2px solid transparent;
    transition: all 0.15s;
    line-height: 1.5;

    &:hover {
      color: #2C5F8A;
      background: #ebf2fa;
      border-left-color: #2C5F8A;
    }

    &.active {
      color: #2C5F8A;
      font-weight: 500;
      border-left-color: #2C5F8A;
      background: rgba(44, 95, 138, 0.04);
    }

    &--t2 {
      padding-left: 24px;
      font-size: 12px;
    }

    &--t3 {
      padding-left: 36px;
      font-size: 11.5px;
      color: #9e9e98;
    }
  }
}

.rdr-toc-overlay {
  display: none;
}

/* Article */
.rdr-article {
  flex: 1;
  min-width: 0;
  padding: 40px 0 80px;
}

/* Markdown body styles — scoped under .rdr-article to avoid global conflict */
.rdr-article .md-body {
  h1 { font-size: 28px; font-weight: 700; letter-spacing: -0.5px; line-height: 1.3; margin: 0 0 16px; color: #1a1a18; }
  h2 { font-size: 22px; font-weight: 600; margin: 48px 0 16px; padding-bottom: 10px; border-bottom: 1px solid #e5e4df; color: #1a1a18; display: flex; align-items: center; gap: 10px;
    &::before { content: ''; width: 4px; height: 22px; background: #2C5F8A; border-radius: 2px; flex-shrink: 0; }
  }
  h3 { font-size: 18px; font-weight: 600; margin: 32px 0 12px; color: #1a1a18; }
  h4 { font-size: 16px; font-weight: 600; margin: 24px 0 8px; color: #1a1a18; }
  h5 { font-size: 15px; font-weight: 600; margin: 20px 0 8px; color: #6b6b66; }
  p { margin: 0 0 16px; color: #1a1a18; max-width: 720px; line-height: 1.8; }
  strong { font-weight: 600; }
  em { font-style: italic; color: #6b6b66; }
  a { color: #2C5F8A; text-decoration: none; border-bottom: 1px solid rgba(44, 95, 138, 0.3);
    &:hover { border-bottom-color: #2C5F8A; }
  }
  ul, ol { margin: 0 0 16px; padding-left: 24px; max-width: 720px; }
  li { margin: 4px 0; line-height: 1.7; }
  li p { margin: 4px 0; }
  blockquote { border-left: 3px solid #2C5F8A; background: #ebf2fa; margin: 16px 0; padding: 12px 20px; border-radius: 0 8px 8px 0; max-width: 720px;
    p { margin: 4px 0; color: #6b6b66; font-size: 14px; }
  }
  .table-wrap { overflow-x: auto; margin: 16px 0 24px; border-radius: 8px; }
  table { width: 100%; border-collapse: collapse; font-size: 13px; background: #fff; border: 1px solid #e5e4df; border-radius: 8px; overflow: hidden; }
  thead th { background: #f3f2ee; padding: 10px 14px; text-align: center; font-weight: 600; font-size: 12px; color: #6b6b66; border-bottom: 1px solid #e5e4df; }
  tbody td { padding: 8px 14px; text-align: center; border-bottom: 1px solid #e5e4df; line-height: 1.6; }
  tbody td:first-child { font-weight: 500; }
  tbody tr:last-child td { border-bottom: none; }
  tbody tr:hover { background: rgba(44, 95, 138, 0.02); }
  code { font-size: 13px; background: #f3f2ee; padding: 2px 6px; border-radius: 4px; color: #c0392b; }
  pre { background: #2b2d30; color: #d4d4d4; padding: 16px 20px; border-radius: 8px; margin: 16px 0 24px; overflow-x: auto; font-size: 13px; line-height: 1.6;
    code { background: none; padding: 0; color: inherit; }
  }
  hr { border: none; height: 1px; background: #e5e4df; margin: 40px 0; }
  img { max-width: 100%; border-radius: 8px; margin: 16px 0; }
}

/* Floating action buttons */
.rdr-fab-group {
  position: fixed;
  bottom: 32px;
  right: 32px;
  z-index: 1010;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.rdr-fab.ant-btn {
  width: 40px;
  height: 40px;
  background: #fff;
  border: 1px solid #e5e4df;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
  color: #6b6b66;
  font-size: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 1;
  transition: all 0.3s;

  &:hover { background: #ebf2fa; border-color: #2C5F8A; color: #2C5F8A; }

  /* Back-to-top button hidden until scrolled */
  &:not(.show):last-child { opacity: 0; transform: translateY(10px); pointer-events: none; }
  &.show { opacity: 1; transform: translateY(0); pointer-events: auto; }
}

/* Mobile */
@media (max-width: 900px) {
  .rdr-toc {
    display: none;
    position: fixed;
    top: 52px;
    left: 0;
    width: 280px;
    height: calc(100vh - 52px);
    background: #fff;
    border-right: 1px solid #e5e4df;
    z-index: 90;
    padding: 20px 12px;
    box-shadow: 4px 0 24px rgba(0, 0, 0, 0.08);

    &--open { display: block; }
  }

  .rdr-toc-overlay {
    display: none;
    position: fixed;
    inset: 0;
    top: 52px;
    background: rgba(0, 0, 0, 0.2);
    z-index: 89;

    &:has(~ .rdr-toc--open) { display: block; }
  }

  .rdr-topbar__toc-btn { display: block !important; }
  .rdr-layout { padding: 0 16px; }
  .rdr-article { padding: 24px 0 60px; }
  .md-body h1 { font-size: 24px; }
  .md-body h2 { font-size: 19px; }
  .rdr-fab-group { bottom: 20px; right: 20px; }
}

/* Print */
@media print {
  .rdr-topbar, .rdr-toc, .rdr-fab-group, .rdr-progress, .rdr-toc-overlay { display: none !important; }
  .rdr-layout { display: block; }
  .rdr-article { padding: 0; }
  .md-body h2 { break-before: page; }
}
</style>
