<template>
  <GuidePageFrame
    :active-tab="activeTopTab"
    variant="static"
    :show-top-tabs="false"
    show-back
    @back="handleBack"
  >
    <view class="explain-detail-page" :class="{ 'with-audio-player': showAudioPlayer }">
      <scroll-view class="content" scroll-y :show-scrollbar="false">
        <image
          v-if="heroImage"
          class="hero-image"
          :src="heroImage"
          mode="aspectFill"
        />

        <view v-else class="hero-placeholder">
          <text class="hero-placeholder-text">讲解</text>
        </view>

        <view class="detail-body">
          <text class="detail-title">{{ exhibit.title }}</text>
          <text v-if="detailMeta" class="detail-meta">{{ detailMeta }}</text>

          <view
            v-if="exhibit.audio.status === 'playable'"
            class="audio-panel"
            @tap="handlePlayAudio"
          >
            <view class="audio-play">
              <svg v-if="!isPlaying" width="24" height="24" viewBox="0 0 24 24" fill="none">
                <path d="M8 5V19L19 12L8 5Z" fill="currentColor"/>
              </svg>
              <svg v-else width="24" height="24" viewBox="0 0 24 24" fill="none">
                <rect x="6" y="5" width="4" height="14" rx="1" fill="currentColor"/>
                <rect x="14" y="5" width="4" height="14" rx="1" fill="currentColor"/>
              </svg>
            </view>
            <text class="audio-time">00:00</text>
            <view class="audio-track">
              <view class="audio-dot"></view>
            </view>
            <text class="audio-time">{{ exhibit.audio.durationLabel || '音频讲解' }}</text>
          </view>

          <view v-else class="text-status-panel">
            <text class="text-status-title">图文讲解</text>
            <text class="text-status-desc">
              {{ exhibit.audio.unavailableReason || '该讲解暂无已发布音频，当前提供图文讲解。' }}
            </text>
          </view>

          <view class="content-section">
            <text class="section-title">讲解内容</text>
            <text class="section-text">{{ exhibit.body || exhibit.summary }}</text>
          </view>
        </view>
      </scroll-view>

      <view class="action-bar">
        <view
          class="location-btn"
          :class="{ disabled: !hallLocationId }"
          @tap="handleNavigate"
        >
          <svg class="location-icon" width="19" height="19" viewBox="0 0 24 24" fill="none">
            <path d="M12 21C12 21 18 14.9 18 9.8C18 6.5 15.3 4 12 4C8.7 4 6 6.5 6 9.8C6 14.9 12 21 12 21Z" stroke="currentColor" stroke-width="1.7"/>
            <circle cx="12" cy="10" r="2.2" stroke="currentColor" stroke-width="1.7"/>
          </svg>
          <text class="location-text">查看位置</text>
        </view>
      </view>

      <AudioPlayer
        ref="audioPlayerRef"
        :visible="showAudioPlayer"
        :audio="currentAudio"
        :auto-play="true"
        @update:visible="handleAudioVisibleChange"
        @play="handleAudioPlay"
        @pause="handleAudioPause"
        @ended="handleAudioEnded"
        @error="handleAudioError"
      />
    </view>
  </GuidePageFrame>
</template>

<script setup lang="ts">
import { computed, nextTick, ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import GuidePageFrame from '@/components/navigation/GuidePageFrame.vue'
import AudioPlayer, { type AudioItem } from '@/components/audio/AudioPlayer.vue'
import {
  explainUseCase
} from '@/usecases/explainUseCase'
import {
  guideUseCase
} from '@/usecases/guideUseCase'
import {
  toExplainDetailPageViewModel,
  type ExplainDetailPageViewModel
} from '@/view-models/explainViewModels'
import {
  isGuideTopTab,
  type GuideTopTab
} from '@/utils/guideTopTabs'

const defaultDetail: ExplainDetailPageViewModel = {
  id: '',
  title: '讲解内容',
  subtitle: '位置待补充',
  contentType: 'exhibit',
  coverImages: [],
  summary: '该讲解内容待补充。',
  body: '该讲解内容待补充。',
  audio: {
    status: 'unavailable',
    unavailableReason: '该讲解暂无已发布音频，当前提供图文讲解。'
  },
  chapters: [],
  relatedItems: []
}

interface AudioPlayerExpose {
  play: (audio: AudioItem) => void
  pause: () => void
}

const exhibit = ref<ExplainDetailPageViewModel>(defaultDetail)
const audioPlayerRef = ref<AudioPlayerExpose | null>(null)
const showAudioPlayer = ref(false)
const currentAudio = ref<AudioItem | null>(null)
const isPlaying = ref(false)
const activeTopTab = ref<GuideTopTab>('explain')
const resolvedHallId = ref('')

const heroImage = computed(() => exhibit.value.coverImages[0])
const detailMeta = computed(() => [
  exhibit.value.hallName,
  exhibit.value.floorLabel
].filter(Boolean).join(' · '))
const hallLocationId = computed(() => exhibit.value.hallId || resolvedHallId.value)

const normalizePoiName = (value: string) => value
  .trim()
  .replace(/[\s（）()【】[\]_-]/g, '')
  .toLowerCase()

// 讲解详情页只定位到所属展厅，不再追踪具体展品点位。
const resolveHallGuidePoi = async () => {
  const hallId = exhibit.value.hallId
  if (hallId) {
    const hallPoi = await guideUseCase.getPoiById(hallId)
    if (hallPoi?.kind === 'hall' || hallPoi?.primaryCategory.id === 'exhibition_hall') {
      return hallPoi
    }
  }

  const normalizedTarget = normalizePoiName(exhibit.value.hallName || '')
  if (!normalizedTarget) return null

  const candidates = await guideUseCase.searchPois(exhibit.value.hallName || exhibit.value.title || '')
  return candidates.find((candidate) => {
    const candidateName = normalizePoiName(candidate.name)
    const candidateHallName = normalizePoiName(candidate.hallName || '')
    return candidate.kind === 'hall'
      || candidate.primaryCategory.id === 'exhibition_hall'
      || candidateName === normalizedTarget
      || candidateHallName === normalizedTarget
      || candidateName.includes(normalizedTarget)
      || normalizedTarget.includes(candidateName)
  }) || candidates[0] || null
}

onLoad(async (options: any = {}) => {
  const tab = Array.isArray(options.tab) ? options.tab[0] : options.tab
  if (isGuideTopTab(tab)) {
    activeTopTab.value = tab
  }

  const exhibitId = Array.isArray(options.id) ? options.id[0] : options.id
  if (!exhibitId) return

  const exhibitData = await explainUseCase.getExhibitById(exhibitId)
  if (exhibitData) {
    exhibit.value = toExplainDetailPageViewModel(exhibitData)
    if (exhibitData.hallId) {
      resolvedHallId.value = exhibitData.hallId
    }
  }
})

const handlePlayAudio = async () => {
  if (exhibit.value.audio.url) {
    const audio: AudioItem = {
      id: `media-${exhibit.value.id}`,
      name: exhibit.value.title,
      audioUrl: exhibit.value.audio.url,
      image: heroImage.value,
      duration: undefined
    }

    const isSameAudio = currentAudio.value?.id === audio.id
    if (showAudioPlayer.value && isSameAudio && isPlaying.value) {
      audioPlayerRef.value?.pause()
      return
    }

    showAudioPlayer.value = true
    currentAudio.value = audio
    await nextTick()

    if (!isPlaying.value) {
      audioPlayerRef.value?.play(audio)
    }
    return
  }

  const selection = exhibit.value.id
    ? await explainUseCase.selectAudioForExhibit(exhibit.value.id)
    : null

  if (!selection?.playable || !selection.media?.url) {
    uni.showToast({
      title: selection?.unavailableMessage || exhibit.value.audio.unavailableReason || '该讲解暂无可播放音频',
      icon: 'none'
    })
    return
  }

  const audio: AudioItem = {
    id: selection.media.id,
    name: selection.track?.title || selection.exhibit.name,
    audioUrl: selection.media.url,
    image: selection.exhibit.image || heroImage.value,
    duration: selection.media.duration
  }

  const isSameAudio = currentAudio.value?.id === audio.id
  if (showAudioPlayer.value && isSameAudio && isPlaying.value) {
    audioPlayerRef.value?.pause()
    return
  }

  showAudioPlayer.value = true
  currentAudio.value = audio
  await nextTick()

  if (!isPlaying.value) {
    audioPlayerRef.value?.play(audio)
  }
}

const handleAudioVisibleChange = (visible: boolean) => {
  showAudioPlayer.value = visible
  if (!visible) {
    isPlaying.value = false
    currentAudio.value = null
  }
}

const handleAudioPlay = () => {
  isPlaying.value = true
}

const handleAudioPause = () => {
  isPlaying.value = false
}

const handleAudioEnded = () => {
  isPlaying.value = false
  showAudioPlayer.value = false
  currentAudio.value = null
}

const handleAudioError = (_audio: AudioItem | null, message: string) => {
  console.warn('详情音频不可播放:', message)
  isPlaying.value = false
  showAudioPlayer.value = false
  currentAudio.value = null
}

const handleNavigate = async () => {
  const matchedHallPoi = await resolveHallGuidePoi()
  if (!matchedHallPoi) {
    uni.showToast({
      title: '该讲解暂无所属展厅位置数据',
      icon: 'none'
    })
    return
  }

  resolvedHallId.value = matchedHallPoi.id
  exhibit.value = {
    ...exhibit.value,
    hallId: matchedHallPoi.id,
    hallName: matchedHallPoi.hallName || matchedHallPoi.name,
    location: exhibit.value.location || {
      status: 'hallFallback',
      poiId: matchedHallPoi.id,
      sourcePoiId: matchedHallPoi.id,
      actionText: '查看所属展厅',
      previewOnly: true,
      floorId: matchedHallPoi.floorId,
      floorLabel: matchedHallPoi.floorLabel,
      note: '已定位到该讲解所属展厅。'
    }
  }

  uni.navigateTo({
    url: `/pages/route/detail?facilityId=${encodeURIComponent(matchedHallPoi.id)}&target=${encodeURIComponent(exhibit.value.hallName || exhibit.value.title)}&state=preview`
  })
}

const handleBack = () => {
  uni.navigateBack({
    delta: 1,
    fail: () => {
      uni.reLaunch({
        url: '/pages/index/index?tab=explain'
      })
    }
  })
}
</script>

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

.content {
  height: 100%;
  padding: 84px 20px calc(104px + env(safe-area-inset-bottom));
  box-sizing: border-box;
}

.hero-image,
.hero-placeholder {
  width: 100%;
  height: 250px;
  border-radius: 8px;
}

.hero-image {
  background: #e9ece5;
}

.hero-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  background: #e9ece5;
}

.hero-placeholder-text {
  font-size: 20px;
  line-height: 28px;
  font-weight: 800;
  color: #68725d;
}

.detail-body {
  padding-top: 22px;
}

.detail-title,
.detail-meta,
.audio-time,
.text-status-title,
.text-status-desc,
.section-title,
.section-text,
.location-text {
  display: block;
}

.detail-title {
  font-size: 29px;
  line-height: 38px;
  font-weight: 800;
  color: #151713;
}

.detail-meta {
  margin-top: 8px;
  font-size: 16px;
  line-height: 22px;
  color: #555c51;
}

.audio-panel {
  height: 76px;
  margin-top: 24px;
  padding: 0 15px;
  display: flex;
  align-items: center;
  gap: 14px;
  box-sizing: border-box;
  background: #0b0c0a;
  border-radius: 8px;
  color: #ffffff;
}

.audio-play {
  flex-shrink: 0;
  width: 42px;
  height: 42px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  color: #151713;
  background: #e0df00;
}

.audio-time {
  flex-shrink: 0;
  font-size: 14px;
  line-height: 20px;
  color: #ffffff;
}

.audio-track {
  position: relative;
  flex: 1;
  height: 3px;
  background: rgba(255, 255, 255, 0.24);
  border-radius: 999px;
}

.audio-dot {
  position: absolute;
  top: 50%;
  left: 0;
  width: 12px;
  height: 12px;
  background: #e0df00;
  border-radius: 50%;
  transform: translateY(-50%);
}

.text-status-panel {
  margin-top: 24px;
  padding: 14px;
  box-sizing: border-box;
  background: #ffffff;
  border: 1px solid #e4e6df;
  border-radius: 8px;
}

.text-status-title {
  font-size: 15px;
  line-height: 21px;
  font-weight: 800;
  color: #151713;
}

.text-status-desc {
  margin-top: 5px;
  font-size: 13px;
  line-height: 20px;
  color: #5d6656;
}

.content-section {
  margin-top: 28px;
}

.section-title {
  font-size: 19px;
  line-height: 27px;
  font-weight: 800;
  color: #151713;
}

.section-text {
  margin-top: 13px;
  font-size: 16px;
  line-height: 28px;
  color: #2f352d;
  white-space: pre-line;
}

.action-bar {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 12px 20px calc(18px + env(safe-area-inset-bottom));
  box-sizing: border-box;
  background: rgba(249, 250, 251, 0.96);
}

.explain-detail-page.with-audio-player .action-bar {
  bottom: 88px;
}

.location-btn {
  height: 52px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  box-sizing: border-box;
  background: #ffffff;
  border: 1px solid #151713;
  border-radius: 8px;
  color: #151713;
}

.location-btn.disabled {
  color: #8d9488;
  border-color: #d8dcd3;
  background: #f2f4ef;
}

.location-icon {
  flex-shrink: 0;
}

.location-text {
  font-size: 16px;
  line-height: 22px;
  font-weight: 700;
  color: currentColor;
}
</style>
