<template>
  <view class="explain-list">
    <view class="spatial-stage">
      <view class="stage-copy">
        <text class="stage-kicker">空间讲解</text>
        <text class="stage-title">{{ activeFloorLabel }} · {{ filteredCards.length }} 个讲解点</text>
        <text class="stage-desc">
          {{ playableCount }} 个可播放音频 · {{ hallSummaries.length }} 个展厅
        </text>
      </view>
      <view class="stage-map">
        <view class="stage-floor">
          <text class="stage-floor-text">{{ activeFloorLabel }}</text>
        </view>
        <view
          v-for="(marker, index) in previewMarkers"
          :key="marker.id"
          class="stage-marker"
          :class="`marker-${index + 1}`"
        ></view>
      </view>
    </view>

    <view class="content-panel">
      <view class="panel-handle"></view>

      <view class="panel-summary">
        <view class="summary-main">
          <text class="summary-title">当前楼层 {{ activeFloorLabel }}</text>
          <text class="summary-subtitle">
            {{ filteredCards.length }} 个讲解点 · {{ unavailableAudioCount }} 个音频待开放
          </text>
        </view>
        <view class="summary-chip">
          <text class="summary-chip-text">位置预览</text>
        </view>
      </view>

      <view class="search-box">
        <svg class="search-icon" width="20" height="20" viewBox="0 0 20 20" fill="none">
          <circle cx="8.5" cy="8.5" r="5.5" stroke="currentColor" stroke-width="1.5"/>
          <path d="M12.5 12.5L17 17" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
        </svg>
        <input
          class="search-input"
          type="text"
          placeholder="搜索讲解、展厅、主题"
          v-model="searchInputValue"
          @input="handleSearchInput"
          @confirm="handleSearchConfirm"
        />
        <view v-if="searchInputValue" class="clear-btn" @tap="handleClearSearch">
          <svg width="14" height="14" viewBox="0 0 14 14" fill="none">
            <circle cx="7" cy="7" r="6" fill="#8b9183"/>
            <path d="M4.5 4.5L9.5 9.5M9.5 4.5L4.5 9.5" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
          </svg>
        </view>
      </view>

      <scroll-view class="panel-scroll" :scroll-y="true" :show-scrollbar="false">
        <view v-if="loading" class="state-block">
          <text class="state-title">正在加载讲解内容</text>
          <text class="state-desc">稍后将展示当前楼层和展厅讲解点。</text>
        </view>

        <view v-else-if="error" class="state-block error">
          <text class="state-title">讲解内容加载失败</text>
          <text class="state-desc">{{ error }}</text>
        </view>

        <template v-else>
          <view v-if="featuredCard" class="featured-section">
            <view class="section-heading">
              <text class="section-title">今日推荐讲解</text>
              <text class="section-count">{{ featuredCard.audioStatusText }}</text>
            </view>
            <view class="featured-card" @tap="handleCardClick(featuredCard)">
              <image
                v-if="featuredCard.coverImage"
                class="featured-cover"
                :src="featuredCard.coverImage"
                mode="aspectFill"
              />
              <view v-else class="featured-cover placeholder">
                <text class="placeholder-text">{{ contentTypeText(featuredCard.contentType).slice(0, 1) }}</text>
              </view>
              <view class="featured-body">
                <text class="featured-title">{{ featuredCard.title }}</text>
                <text class="featured-meta">{{ cardMeta(featuredCard) }}</text>
                <text class="featured-summary">{{ featuredCard.summary || '正式讲解文案待内容库接入后完善。' }}</text>
                <view class="featured-actions">
                  <view
                    v-if="featuredCard.audioStatus === 'playable'"
                    class="action-btn primary"
                    @tap.stop="handleAudioClick(featuredCard)"
                  >
                    <text class="action-text primary">开始讲解</text>
                  </view>
                  <view v-else class="action-btn disabled">
                    <text class="action-text disabled">{{ featuredCard.audioStatusText }}</text>
                  </view>
                  <view
                    v-if="featuredCard.poiId"
                    class="action-btn secondary"
                    @tap.stop="handleLocationClick(featuredCard)"
                  >
                    <text class="action-text">查看位置</text>
                  </view>
                </view>
              </view>
            </view>
          </view>

          <view class="filter-section">
            <view
              v-for="filter in resolvedFilters"
              :key="filter.id"
              class="filter-chip"
              :class="{ active: activeFilter === filter.id }"
              @tap="handleFilterChange(filter.id)"
            >
              <text class="filter-text">{{ filter.label }}</text>
              <text v-if="typeof filter.count === 'number'" class="filter-count">{{ filter.count }}</text>
            </view>
          </view>

          <view v-if="hallSummaries.length" class="hall-section">
            <view class="section-heading">
              <text class="section-title">展厅讲解</text>
              <text class="section-count">{{ hallSummaries.length }} 个展厅</text>
            </view>
            <view class="hall-grid">
              <view
                v-for="hall in hallSummaries"
                :key="hall.name"
                class="hall-chip"
                @tap="handleHallFilter(hall.name)"
              >
                <text class="hall-name">{{ hall.name }}</text>
                <text class="hall-count">{{ hall.count }}</text>
              </view>
            </view>
          </view>

          <view class="list-section">
            <view class="section-heading">
              <text class="section-title">讲解列表</text>
              <text class="section-count">{{ displayedCards.length }} 条</text>
            </view>

            <view v-if="displayedCards.length" class="card-list">
              <view
                v-for="card in displayedCards"
                :key="card.id"
                class="explain-card"
                @tap="handleCardClick(card)"
              >
                <view class="card-main">
                  <view class="card-title-row">
                    <text class="card-title">{{ card.title }}</text>
                    <view class="status-pill" :class="`status-${card.audioStatus}`">
                      <text class="status-text">{{ card.audioStatusText }}</text>
                    </view>
                  </view>
                  <text class="card-meta">{{ cardMeta(card) }}</text>
                  <text v-if="card.summary" class="card-summary">{{ card.summary }}</text>
                  <view class="badge-row">
                    <text
                      v-for="badge in normalizedBadges(card)"
                      :key="`${card.id}-${badge}`"
                      class="badge"
                    >
                      {{ badge }}
                    </text>
                  </view>
                </view>
                <view class="card-actions">
                  <view
                    v-if="card.audioStatus === 'playable'"
                    class="small-action primary"
                    @tap.stop="handleAudioClick(card)"
                  >
                    <text class="small-action-text primary">播放</text>
                  </view>
                  <view class="small-action" @tap.stop="handleCardClick(card)">
                    <text class="small-action-text">详情</text>
                  </view>
                  <view
                    v-if="card.poiId"
                    class="small-action"
                    @tap.stop="handleLocationClick(card)"
                  >
                    <text class="small-action-text">位置</text>
                  </view>
                </view>
              </view>
            </view>

            <view v-else class="state-block empty">
              <text class="state-title">未找到相关讲解</text>
              <text class="state-desc">试试展厅名称、楼层或主题关键词。</text>
            </view>
          </view>
        </template>
      </scroll-view>
    </view>
  </view>
</template>

<script setup lang="ts">
import { computed, ref } from 'vue'
import type {
  ExplainCardViewModel
} from '@/view-models/explainViewModels'

export interface ExplainFilterOption {
  id: 'all' | 'hall' | 'theme' | 'nearby' | 'playable'
  label: string
  count?: number
}

export type Exhibit = ExplainCardViewModel

const props = withDefaults(defineProps<{
  cards?: ExplainCardViewModel[]
  exhibits?: ExplainCardViewModel[]
  filters?: ExplainFilterOption[]
  loading?: boolean
  error?: string
  hotSearches?: string[]
}>(), {
  cards: () => [],
  exhibits: () => [],
  filters: () => [],
  loading: false,
  error: '',
  hotSearches: () => []
})

const emit = defineEmits<{
  exhibitClick: [card: ExplainCardViewModel]
  featuredClick: [card: ExplainCardViewModel]
  audioClick: [card: ExplainCardViewModel]
  locationClick: [card: ExplainCardViewModel]
  filterChange: [filter: ExplainFilterOption['id']]
  search: [keyword: string]
}>()

const searchInputValue = ref('')
const activeFilter = ref<ExplainFilterOption['id']>('all')
const activeHallName = ref('')

const cards = computed(() => props.cards.length ? props.cards : props.exhibits)

const playableCount = computed(() => cards.value.filter((card) => card.audioStatus === 'playable').length)
const unavailableAudioCount = computed(() => cards.value.filter((card) => card.audioStatus === 'unavailable').length)

const hallSummaries = computed(() => {
  const result = new Map<string, number>()
  cards.value.forEach((card) => {
    const hallName = card.hallName || '未分配展厅'
    result.set(hallName, (result.get(hallName) || 0) + 1)
  })
  return Array.from(result.entries())
    .map(([name, count]) => ({ name, count }))
    .sort((a, b) => b.count - a.count)
})

const activeFloorLabel = computed(() => {
  const counts = new Map<string, number>()
  cards.value.forEach((card) => {
    if (card.floorLabel) {
      counts.set(card.floorLabel, (counts.get(card.floorLabel) || 0) + 1)
    }
  })

  return Array.from(counts.entries()).sort((a, b) => b[1] - a[1])[0]?.[0] || '全馆'
})

const previewMarkers = computed(() => cards.value.slice(0, 5))

const resolvedFilters = computed<ExplainFilterOption[]>(() => props.filters.length ? props.filters : [
  { id: 'all', label: '全部', count: cards.value.length },
  { id: 'hall', label: '展厅', count: hallSummaries.value.length },
  { id: 'theme', label: '主题', count: props.hotSearches.length || hallSummaries.value.length },
  { id: 'nearby', label: '附近', count: cards.value.filter((card) => card.floorLabel === activeFloorLabel.value).length },
  { id: 'playable', label: '可播放', count: playableCount.value }
])

const keywordMatchedCards = computed(() => {
  const keyword = searchInputValue.value.trim().toLowerCase()
  if (!keyword) return cards.value

  return cards.value.filter((card) => [
    card.title,
    card.subtitle,
    card.summary,
    card.hallName,
    card.floorLabel,
    card.audioStatusText,
    contentTypeText(card.contentType),
    ...card.badges
  ].filter(Boolean).join(' ').toLowerCase().includes(keyword))
})

const filteredCards = computed(() => {
  let result = keywordMatchedCards.value

  if (activeHallName.value) {
    result = result.filter((card) => card.hallName === activeHallName.value)
  }

  if (activeFilter.value === 'nearby') {
    result = result.filter((card) => card.floorLabel === activeFloorLabel.value)
  }

  if (activeFilter.value === 'playable') {
    result = result.filter((card) => card.audioStatus === 'playable')
  }

  return result
})

const displayedCards = computed(() => filteredCards.value)
const featuredCard = computed(() => cards.value.find((card) => card.audioStatus === 'playable') || cards.value[0])

const contentTypeText = (type: ExplainCardViewModel['contentType']) => {
  const textMap: Record<ExplainCardViewModel['contentType'], string> = {
    hall: '展厅讲解',
    zone: '展区讲解',
    exhibit: '讲解点',
    theme: '主题讲解'
  }
  return textMap[type]
}

const cardMeta = (card: ExplainCardViewModel) => [
  card.hallName,
  card.floorLabel,
  card.durationLabel,
  card.languageLabel,
  contentTypeText(card.contentType)
].filter(Boolean).join(' · ')

const normalizedBadges = (card: ExplainCardViewModel) => {
  const badges = card.badges.length ? card.badges : [contentTypeText(card.contentType)]
  return badges.slice(0, 3)
}

const handleSearchInput = () => {
  emit('search', searchInputValue.value)
}

const handleSearchConfirm = () => {
  emit('search', searchInputValue.value.trim())
}

const handleClearSearch = () => {
  searchInputValue.value = ''
  activeHallName.value = ''
  emit('search', '')
}

const handleFilterChange = (filter: ExplainFilterOption['id']) => {
  activeFilter.value = filter
  if (filter !== 'hall') {
    activeHallName.value = ''
  }
  emit('filterChange', filter)
}

const handleHallFilter = (hallName: string) => {
  activeFilter.value = 'hall'
  activeHallName.value = activeHallName.value === hallName ? '' : hallName
  emit('filterChange', 'hall')
}

const handleCardClick = (card: ExplainCardViewModel) => {
  emit('exhibitClick', card)
}

const handleAudioClick = (card: ExplainCardViewModel) => {
  emit('audioClick', card)
}

const handleLocationClick = (card: ExplainCardViewModel) => {
  emit('locationClick', card)
}
</script>

<style scoped lang="scss">
.explain-list {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: #edf0ea;
}

.spatial-stage {
  position: absolute;
  top: 44px;
  left: 0;
  right: 0;
  height: 298px;
  padding: 18px 16px 0;
  box-sizing: border-box;
  background: #dfe5dc;
}

.stage-copy {
  position: relative;
  z-index: 2;
  width: 220px;
}

.stage-kicker,
.stage-title,
.stage-desc {
  display: block;
}

.stage-kicker {
  font-size: 12px;
  line-height: 16px;
  color: #5e6658;
}

.stage-title {
  margin-top: 4px;
  font-size: 22px;
  line-height: 30px;
  font-weight: 700;
  color: #151713;
}

.stage-desc {
  margin-top: 6px;
  font-size: 13px;
  line-height: 18px;
  color: #5e6658;
}

.stage-map {
  position: absolute;
  left: 26px;
  right: 26px;
  bottom: 38px;
  height: 128px;
  border: 1px solid rgba(88, 95, 78, 0.2);
  border-radius: 8px;
  background: #f4f5ef;
  overflow: hidden;
}

.stage-map::before,
.stage-map::after {
  content: '';
  position: absolute;
  left: 32px;
  right: 32px;
  height: 1px;
  background: rgba(88, 95, 78, 0.2);
}

.stage-map::before {
  top: 42px;
}

.stage-map::after {
  top: 84px;
}

.stage-floor {
  position: absolute;
  right: 12px;
  top: 12px;
  min-width: 44px;
  height: 28px;
  padding: 0 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  background: #151713;
  border-radius: 6px;
}

.stage-floor-text {
  font-size: 12px;
  font-weight: 600;
  color: var(--museum-accent);
}

.stage-marker {
  position: absolute;
  width: 14px;
  height: 14px;
  background: #2f7d59;
  border: 3px solid #ffffff;
  border-radius: 50%;
  box-shadow: 0 3px 8px rgba(0, 0, 0, 0.2);
}

.marker-1 {
  left: 28%;
  top: 36%;
}

.marker-2 {
  left: 48%;
  top: 54%;
}

.marker-3 {
  left: 62%;
  top: 30%;
}

.marker-4 {
  left: 74%;
  top: 62%;
}

.marker-5 {
  left: 38%;
  top: 68%;
}

.content-panel {
  position: absolute;
  left: 0;
  right: 0;
  top: 232px;
  bottom: 0;
  display: flex;
  flex-direction: column;
  box-sizing: border-box;
  background: #ffffff;
  border-radius: 16px 16px 0 0;
  box-shadow: 0 -8px 28px rgba(25, 28, 21, 0.08);
  z-index: 10;
}

.panel-handle {
  align-self: center;
  width: 64px;
  height: 4px;
  margin-top: 8px;
  border-radius: 2px;
  background: #d9ddd3;
}

.panel-summary {
  flex-shrink: 0;
  padding: 12px 16px 10px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  box-sizing: border-box;
}

.summary-main {
  min-width: 0;
}

.summary-title,
.summary-subtitle {
  display: block;
}

.summary-title {
  font-size: 18px;
  line-height: 25px;
  font-weight: 700;
  color: #151713;
}

.summary-subtitle {
  margin-top: 2px;
  font-size: 12px;
  line-height: 16px;
  color: #697064;
}

.summary-chip {
  flex-shrink: 0;
  height: 28px;
  padding: 0 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #eef1e8;
  border-radius: 6px;
}

.summary-chip-text {
  font-size: 12px;
  color: #495143;
}

.search-box {
  flex-shrink: 0;
  margin: 0 16px 12px;
  height: 42px;
  display: flex;
  align-items: center;
  box-sizing: border-box;
  background: #f5f6f1;
  border: 1px solid #e2e5dc;
  border-radius: 8px;
  padding: 0 12px;
}

.search-icon {
  flex-shrink: 0;
  color: #596052;
  margin-right: 8px;
}

.search-input {
  flex: 1;
  min-width: 0;
  height: 40px;
  font-size: 14px;
  color: #151713;
  background: transparent;
}

.clear-btn {
  flex-shrink: 0;
  width: 22px;
  height: 22px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.panel-scroll {
  flex: 1;
  height: 0;
  padding: 0 16px;
  box-sizing: border-box;
}

.section-heading {
  margin: 12px 0 10px;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.section-title {
  font-size: 15px;
  line-height: 21px;
  font-weight: 700;
  color: #151713;
}

.section-count {
  font-size: 12px;
  color: #788072;
}

.featured-card {
  display: flex;
  padding: 10px;
  box-sizing: border-box;
  background: #f7f8f3;
  border: 1px solid #ebece5;
  border-radius: 8px;
}

.featured-cover {
  flex-shrink: 0;
  width: 82px;
  height: 94px;
  border-radius: 8px;
  background: #e5e8df;
}

.featured-cover.placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
}

.placeholder-text {
  font-size: 18px;
  font-weight: 700;
  color: #68725d;
}

.featured-body {
  flex: 1;
  min-width: 0;
  margin-left: 12px;
}

.featured-title,
.featured-meta,
.featured-summary {
  display: block;
}

.featured-title {
  font-size: 17px;
  line-height: 24px;
  font-weight: 700;
  color: #151713;
}

.featured-meta,
.card-meta {
  margin-top: 3px;
  font-size: 12px;
  line-height: 17px;
  color: #68725d;
}

.featured-summary,
.card-summary {
  margin-top: 6px;
  font-size: 12px;
  line-height: 18px;
  color: #4f574b;
  display: -webkit-box;
  overflow: hidden;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
}

.featured-actions,
.card-actions,
.filter-section,
.badge-row,
.hall-grid {
  display: flex;
  align-items: center;
}

.featured-actions {
  margin-top: 10px;
  gap: 8px;
}

.action-btn,
.small-action {
  height: 32px;
  padding: 0 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  border-radius: 8px;
  background: #ffffff;
  border: 1px solid #d8dbd1;
}

.action-btn.primary,
.small-action.primary {
  background: #151713;
  border-color: #151713;
}

.action-btn.disabled {
  background: #eef1e8;
  border-color: #eef1e8;
}

.action-text,
.small-action-text {
  font-size: 13px;
  color: #151713;
}

.action-text.primary,
.small-action-text.primary {
  color: var(--museum-accent);
}

.action-text.disabled {
  color: #68725d;
}

.filter-section {
  margin-top: 14px;
  gap: 8px;
  overflow-x: auto;
  padding-bottom: 2px;
}

.filter-chip {
  flex-shrink: 0;
  min-width: 58px;
  height: 34px;
  padding: 0 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  box-sizing: border-box;
  border-radius: 8px;
  background: #f1f3ed;
}

.filter-chip.active {
  background: #151713;
}

.filter-text,
.filter-count {
  font-size: 13px;
  color: #4f574b;
}

.filter-count {
  color: #8b9385;
}

.filter-chip.active .filter-text,
.filter-chip.active .filter-count {
  color: var(--museum-accent);
}

.hall-grid {
  flex-wrap: wrap;
  gap: 8px;
}

.hall-chip {
  width: calc(50% - 4px);
  height: 42px;
  padding: 0 12px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  box-sizing: border-box;
  background: #f7f8f3;
  border: 1px solid #ebece5;
  border-radius: 8px;
}

.hall-name {
  font-size: 13px;
  color: #151713;
}

.hall-count {
  font-size: 13px;
  font-weight: 700;
  color: #68725d;
}

.card-list {
  padding-bottom: calc(28px + env(safe-area-inset-bottom));
}

.explain-card {
  padding: 12px;
  margin-bottom: 10px;
  box-sizing: border-box;
  background: #f7f8f3;
  border: 1px solid #ebece5;
  border-radius: 8px;
}

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

.card-title {
  flex: 1;
  min-width: 0;
  font-size: 16px;
  line-height: 22px;
  font-weight: 700;
  color: #151713;
}

.status-pill {
  flex-shrink: 0;
  height: 24px;
  padding: 0 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  border-radius: 6px;
  background: #eef1e8;
}

.status-playable {
  background: #e5e600;
}

.status-text {
  font-size: 11px;
  color: #4f574b;
}

.status-playable .status-text {
  color: #151713;
  font-weight: 600;
}

.badge-row {
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 8px;
}

.badge {
  height: 22px;
  padding: 0 8px;
  display: flex;
  align-items: center;
  box-sizing: border-box;
  background: #ecefe7;
  border-radius: 6px;
  font-size: 11px;
  color: #596052;
}

.card-actions {
  margin-top: 10px;
  gap: 8px;
}

.small-action {
  height: 30px;
}

.state-block {
  margin: 30px 0;
  padding: 22px 16px;
  box-sizing: border-box;
  text-align: center;
  background: #f7f8f3;
  border: 1px solid #ebece5;
  border-radius: 8px;
}

.state-title,
.state-desc {
  display: block;
}

.state-title {
  font-size: 15px;
  line-height: 21px;
  font-weight: 700;
  color: #151713;
}

.state-desc {
  margin-top: 6px;
  font-size: 12px;
  line-height: 18px;
  color: #68725d;
}

.state-block.error {
  border-color: #e5c2c2;
  background: #fff7f7;
}
</style>
