<script setup lang="ts">
import { computed, ref, watch } from 'vue'
import { fetchDemandGradeVideos } from '../api/demand'
import type { DemandExpansionPoint, DemandGradeItem, DemandVideoItem } from '../types/demand'
import { gradeRank, parseStrategies } from '../types/demand'

const props = defineProps<{
  open: boolean
  categoryName: string
  items: DemandGradeItem[]
  /** When set, auto-select and load videos for this demand_grade id. */
  highlightDemandId?: number | null
  /** When set, prepend a "当前节点" column. */
  nodeName?: string | null
  nodePath?: string | null
  /** Hide the small inline × close button (when parent provides its own). */
  hideInlineClose?: boolean
}>()

const emit = defineEmits<{
  close: []
}>()

const selectedDemandId = ref<number | null>(null)
const videos = ref<DemandVideoItem[]>([])
const videosLoading = ref(false)
const videosError = ref<string | null>(null)
const selectedVid = ref<string | null>(null)

const selectedDemand = computed(
  () => props.items.find((item) => item.id === selectedDemandId.value) ?? null,
)

const selectedStrategies = computed(() => parseStrategies(selectedDemand.value?.strategies))

const sortedItems = computed(() =>
  [...props.items].sort((a, b) => gradeRank(a.grade) - gradeRank(b.grade)),
)

const selectedVideo = computed(
  () => videos.value.find((v) => v.vid === selectedVid.value) ?? null,
)

const hasVideoInstances = computed(() => videos.value.length > 0)

interface TopicPoint {
  title: string
  pointDesc: string
  reason: string
}

interface TopicSection {
  key: string
  label: string
  accent: string
  items: TopicPoint[]
}

const POINT_TYPE_LABELS: Record<string, string> = {
  purpose: '目的点',
  key: '关键点',
  inspiration: '灵感点',
}

const POINT_TYPE_ORDER = ['purpose', 'key', 'inspiration'] as const

function buildTopicSections(points: DemandExpansionPoint[]): TopicSection[] | null {
  if (!points.length) return null

  const grouped = new Map<string, TopicPoint[]>()
  for (const point of points) {
    const key = point.point_type || 'other'
    const items = grouped.get(key) ?? []
    items.push({
      title: point.expanded_text?.trim() || '未命名',
      pointDesc: point.point_desc?.trim() || '',
      reason: point.reason?.trim() || '',
    })
    grouped.set(key, items)
  }

  const sections: TopicSection[] = []
  for (const key of POINT_TYPE_ORDER) {
    const items = grouped.get(key)
    if (!items?.length) continue
    sections.push({
      key,
      label: POINT_TYPE_LABELS[key] ?? key,
      accent: key === 'purpose' ? 'purpose' : key === 'key' ? 'key' : 'inspiration',
      items,
    })
  }

  if (!sections.length) return null
  return sections
}

const topicSections = computed((): TopicSection[] | null => {
  const video = selectedVideo.value
  if (!video) return null
  return buildTopicSections(video.expansion_points ?? [])
})

watch(
  () => props.open,
  (open) => {
    if (open) return
    selectedDemandId.value = null
    videos.value = []
    videosError.value = null
    selectedVid.value = null
  },
)

watch(
  () => [props.highlightDemandId, props.items] as const,
  ([nextId, items]) => {
    if (!props.open) return
    if (!nextId) {
      selectedDemandId.value = null
      videos.value = []
      videosError.value = null
      selectedVid.value = null
      return
    }
    const item = items.find((i) => i.id === nextId)
    if (!item) return
    void selectDemand(item)
  },
  { immediate: true },
)

function gradeClass(grade: string | null | undefined): string {
  const g = (grade || '').toUpperCase()
  return g ? `grade-${g}` : 'grade-none'
}

async function selectDemand(item: DemandGradeItem) {
  if (selectedDemandId.value === item.id) return
  selectedDemandId.value = item.id
  selectedVid.value = null
  videos.value = []
  videosError.value = null
  videosLoading.value = true
  try {
    const res = await fetchDemandGradeVideos(item.id)
    videos.value = res.videos ?? []
  } catch (e) {
    videosError.value = e instanceof Error ? e.message : String(e)
  } finally {
    videosLoading.value = false
  }
}

function selectVideo(video: DemandVideoItem) {
  selectedVid.value = video.vid
}
</script>

<template>
  <div v-if="open" class="path-rail" role="region" :aria-label="`${categoryName} 路径展开`">
    <!-- 当前节点 -->
    <template v-if="nodeName">
      <section class="col col-node">
        <div class="col-head">
          <h3 class="col-title">当前节点</h3>
          <button
            v-if="!hideInlineClose"
            type="button"
            class="close-btn"
            title="收起路径"
            @click="emit('close')"
          >
            ×
          </button>
        </div>
        <div class="card node-card">
          <span class="card-label">分类节点</span>
          <span class="card-value">{{ nodeName }}</span>
          <span v-if="nodePath" class="card-path">{{ nodePath }}</span>
        </div>
      </section>

      <div class="arrow-col" aria-hidden="true">
        <div class="arrow arrow-slate">
          <span class="arrow-line" />
          <span class="arrow-head">▶</span>
        </div>
      </div>
    </template>

    <!-- 节点 → 需求词 -->
    <div class="arrow-col" aria-hidden="true">
      <div class="arrow arrow-blue">
        <span class="arrow-line" />
        <span class="arrow-head">▶</span>
      </div>
    </div>

    <section class="col col-demand">
      <div class="col-head">
        <h3 class="col-title">细节元素 · 需求词</h3>
        <button
          v-if="!nodeName && !hideInlineClose"
          type="button"
          class="close-btn"
          title="收起路径"
          @click="emit('close')"
        >
          ×
        </button>
      </div>
      <div v-if="sortedItems.length" class="card-list">
        <button
          v-for="item in sortedItems"
          :key="item.id"
          type="button"
          class="card demand-card"
          :class="{ active: selectedDemandId === item.id }"
          @click="selectDemand(item)"
        >
          <div class="demand-card-head">
            <span class="card-label">需求词</span>
            <span class="grade-badge" :class="gradeClass(item.grade)">{{ item.grade || '—' }}</span>
          </div>
          <span class="card-value">{{ item.demand_name || '—' }}</span>
          <div v-if="parseStrategies(item.strategies).length" class="strategy-tags">
            <span
              v-for="s in parseStrategies(item.strategies)"
              :key="s"
              class="strategy-tag"
            >{{ s }}</span>
          </div>
        </button>
      </div>
      <div v-else class="empty">暂无需求词</div>
    </section>

    <!-- 需求词 → 视频 -->
    <template v-if="hasVideoInstances">
      <div class="arrow-col" aria-hidden="true">
        <div v-if="selectedDemand" class="arrow arrow-green">
          <span class="arrow-line" />
          <span class="arrow-head">▶</span>
        </div>
      </div>

      <section class="col col-video">
        <h3 class="col-title">真实视频实例</h3>
        <template v-if="selectedDemand">
          <div class="detail-meta">
            <span class="grade-badge" :class="gradeClass(selectedDemand.grade)">
              {{ selectedDemand.grade || '—' }}
            </span>
            <div v-if="selectedStrategies.length" class="strategy-tags">
              <span v-for="s in selectedStrategies" :key="s" class="strategy-tag">{{ s }}</span>
            </div>
          </div>
          <div v-if="videosLoading" class="empty">加载中…</div>
          <div v-else-if="videosError" class="empty error">{{ videosError }}</div>
          <div v-else class="card-list">
            <button
              v-for="video in videos"
              :key="video.vid"
              type="button"
              class="card video-card"
              :class="{ active: selectedVid === video.vid }"
              @click="selectVideo(video)"
            >
              <span class="card-label">Video {{ video.vid }}</span>
              <span class="card-value">{{ video.title || '（无标题）' }}</span>
            </button>
          </div>
        </template>
      </section>

      <!-- 视频 → 选题 -->
      <div class="arrow-col" aria-hidden="true">
        <div v-if="selectedVideo" class="arrow arrow-purple">
          <span class="arrow-line" />
          <span class="arrow-head">▶</span>
        </div>
      </div>

      <section class="col col-topic">
        <h3 class="col-title">选题结果</h3>
        <template v-if="selectedVideo">
          <div v-if="topicSections" class="topic-card">
            <div class="topic-meta">Video {{ selectedVideo.vid }}</div>
            <div class="topic-body">
              <section
                v-for="section in topicSections"
                :key="section.key"
                class="topic-section"
                :class="`accent-${section.accent}`"
              >
                <div class="section-head">
                  <span class="section-label">{{ section.label }}</span>
                  <span class="section-count">{{ section.items.length }}</span>
                </div>
                <div v-if="section.items.length" class="point-list">
                  <article v-for="(item, idx) in section.items" :key="idx" class="point-item">
                    <div class="point-title-row">
                      <span class="point-index">{{ idx + 1 }}</span>
                      <h4 class="point-title">{{ item.title || '未命名' }}</h4>
                    </div>
                    <p v-if="item.pointDesc" class="point-desc">{{ item.pointDesc }}</p>
                    <p v-if="item.reason" class="point-reason">{{ item.reason }}</p>
                  </article>
                </div>
                <div v-else class="section-empty">暂无</div>
              </section>
            </div>
          </div>
          <div v-else class="empty">暂无选题结果</div>
        </template>
        <div v-else class="empty hint">点击视频展开</div>
      </section>
    </template>
  </div>
</template>

<style scoped>
.path-rail {
  display: flex;
  flex-direction: row;
  align-items: stretch;
  gap: 0;
  padding-left: 0;
  min-height: 0;
  height: 100%;
  width: max-content;
  min-width: 100%;
  max-width: 100%;
}

.col {
  width: 220px;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-height: 0;
  height: 100%;
}

.col-topic {
  width: 380px;
}

.col-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
}

.col-title {
  margin: 0;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.03em;
  color: #64748b;
}

.col-demand .col-title {
  color: #1d4ed8;
}

.col-node .col-title {
  color: #334155;
}

.col-video .col-title {
  color: #15803d;
}

.col-topic .col-title {
  color: #7e22ce;
}

.close-btn {
  width: 22px;
  height: 22px;
  border: none;
  border-radius: 4px;
  background: transparent;
  color: #94a3b8;
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
  flex-shrink: 0;
  padding: 0;
}

.close-btn:hover {
  background: #f1f5f9;
  color: #0f172a;
}

.card-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  flex: 1;
  min-height: 80px;
  overflow: auto;
  overscroll-behavior: contain;
  padding-right: 2px;
}

.card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 3px;
  width: 100%;
  padding: 10px 12px;
  border-radius: 10px;
  border: 1.5px solid transparent;
  background: #fff;
  text-align: left;
  cursor: pointer;
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.card:hover {
  box-shadow: 0 3px 10px rgba(15, 23, 42, 0.08);
}

.card-label {
  font-size: 11px;
  font-weight: 600;
  opacity: 0.8;
}

.card-value {
  font-size: 13px;
  font-weight: 600;
  line-height: 1.35;
  word-break: break-word;
  color: #0f172a;
}

.card-path {
  margin-top: 4px;
  font-size: 11px;
  color: #94a3b8;
  line-height: 1.35;
  word-break: break-word;
}

.node-card {
  border-color: #cbd5e1;
  background: linear-gradient(180deg, #f8fafc 0%, #fff 100%);
  cursor: default;
}

.node-card .card-label {
  color: #475569;
}

.demand-card {
  border-color: #93c5fd;
  background: linear-gradient(180deg, #eff6ff 0%, #fff 100%);
}

.demand-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  gap: 8px;
}

.grade-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  height: 20px;
  padding: 0 6px;
  border-radius: 6px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.02em;
  flex-shrink: 0;
}

.grade-badge.grade-S {
  background: #fee2e2;
  color: #b91c1c;
}

.grade-badge.grade-A {
  background: #ffedd5;
  color: #c2410c;
}

.grade-badge.grade-B {
  background: #fef9c3;
  color: #a16207;
}

.grade-badge.grade-C {
  background: #e0f2fe;
  color: #0369a1;
}

.grade-badge.grade-D {
  background: #f1f5f9;
  color: #64748b;
}

.grade-badge.grade-none {
  background: #f1f5f9;
  color: #94a3b8;
}

.strategy-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-top: 2px;
}

.strategy-tag {
  display: inline-flex;
  align-items: center;
  height: 18px;
  padding: 0 6px;
  border-radius: 999px;
  background: rgba(99, 102, 241, 0.12);
  color: #4338ca;
  font-size: 10px;
  font-weight: 600;
  white-space: nowrap;
}

.detail-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-bottom: 6px;
}

.demand-card .card-label {
  color: #1d4ed8;
}

.demand-card.active {
  border-color: #2563eb;
  box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.16);
}

.video-card {
  border-color: #86efac;
  background: linear-gradient(180deg, #f0fdf4 0%, #fff 100%);
}

.video-card .card-label {
  color: #15803d;
  font-variant-numeric: tabular-nums;
}

.video-card.active {
  border-color: #16a34a;
  box-shadow: 0 0 0 3px rgba(22, 163, 74, 0.16);
}

.arrow-col {
  width: 40px;
  flex-shrink: 0;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding-top: 42px;
}

.arrow {
  display: flex;
  align-items: center;
  width: 100%;
}

.arrow-line {
  flex: 1;
  height: 3px;
  border-radius: 999px;
}

.arrow-head {
  font-size: 11px;
  line-height: 1;
  margin-left: -1px;
}

.arrow-blue .arrow-line {
  background: #3b82f6;
}
.arrow-blue .arrow-head {
  color: #3b82f6;
}

.arrow-slate .arrow-line {
  background: #94a3b8;
}
.arrow-slate .arrow-head {
  color: #94a3b8;
}

.arrow-green .arrow-line {
  background: #22c55e;
}
.arrow-green .arrow-head {
  color: #22c55e;
}

.arrow-purple .arrow-line {
  background: #a855f7;
}
.arrow-purple .arrow-head {
  color: #a855f7;
}

.topic-card {
  border: 1.5px solid #d8b4fe;
  border-radius: 12px;
  background: linear-gradient(180deg, #faf5ff 0%, #fff 45%);
  overflow: hidden;
  flex: 1;
  min-height: 80px;
  display: flex;
  flex-direction: column;
}

.topic-meta {
  padding: 8px 12px;
  border-bottom: 1px solid #f3e8ff;
  font-size: 11px;
  font-weight: 600;
  color: #7e22ce;
  font-variant-numeric: tabular-nums;
  flex-shrink: 0;
}

.topic-body {
  padding: 10px 12px 12px;
  overflow: auto;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.topic-section {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.section-head {
  display: flex;
  align-items: center;
  gap: 8px;
}

.section-label {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.02em;
}

.section-count {
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 999px;
  font-size: 10px;
  font-weight: 700;
  line-height: 18px;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.accent-inspiration .section-label {
  color: #c2410c;
}
.accent-inspiration .section-count {
  color: #c2410c;
  background: #ffedd5;
}
.accent-inspiration .point-index {
  background: #ffedd5;
  color: #c2410c;
}

.accent-purpose .section-label {
  color: #1d4ed8;
}
.accent-purpose .section-count {
  color: #1d4ed8;
  background: #dbeafe;
}
.accent-purpose .point-index {
  background: #dbeafe;
  color: #1d4ed8;
}

.accent-key .section-label {
  color: #7e22ce;
}
.accent-key .section-count {
  color: #7e22ce;
  background: #f3e8ff;
}
.accent-key .point-index {
  background: #f3e8ff;
  color: #7e22ce;
}

.point-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.point-item {
  padding: 10px 11px;
  border-radius: 10px;
  background: #fff;
  border: 1px solid #e2e8f0;
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.03);
}

.point-title-row {
  display: flex;
  align-items: flex-start;
  gap: 8px;
}

.point-index {
  flex-shrink: 0;
  width: 18px;
  height: 18px;
  margin-top: 1px;
  border-radius: 5px;
  font-size: 10px;
  font-weight: 700;
  line-height: 18px;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.point-title {
  margin: 0;
  font-size: 13px;
  font-weight: 700;
  line-height: 1.35;
  color: #0f172a;
  word-break: break-word;
}

.point-desc {
  margin: 6px 0 0;
  padding-left: 26px;
  font-size: 12px;
  line-height: 1.55;
  color: #475569;
  white-space: pre-wrap;
  word-break: break-word;
}

.point-reason {
  margin: 4px 0 0;
  padding-left: 26px;
  font-size: 11px;
  line-height: 1.5;
  color: #64748b;
  white-space: pre-wrap;
  word-break: break-word;
}

.section-empty {
  padding: 8px 10px;
  font-size: 12px;
  color: #94a3b8;
  border: 1px dashed #e2e8f0;
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.6);
}

.empty {
  padding: 20px 10px;
  text-align: center;
  color: #94a3b8;
  font-size: 12px;
  border: 1px dashed #e2e8f0;
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.7);
}

.empty.hint {
  border-style: solid;
  background: transparent;
}

.empty.error {
  color: #b91c1c;
  border-color: #fecaca;
  background: #fef2f2;
}

@media (max-height: 800px) {
  .arrow-col {
    padding-top: 32px;
  }
}
</style>
