<script setup lang="ts">
/**
 * 作品详情：hero、简介、技术栈、外链、图集、下一个作品。
 */
import { computed, ref } from 'vue'
import { onLoad, onPullDownRefresh } from '@dcloudio/uni-app'
import AppNavbar from '@/components/layout/AppNavbar.vue'
import AppPageShell from '@/components/layout/AppPageShell.vue'
import { getWork, type Work } from '@/api'
import { resolveMediaUrl, rewriteHtmlMediaUrls } from '@/utils/request'
import { flattenTechStack, openExternalUrl, parseWorkLinks } from '@/utils/content'

const workId = ref('')
const work = ref<Work | null>(null)
const loading = ref(false)
const showVideo = ref(false)

const heroUrl = computed(() => resolveMediaUrl(String(work.value?.heroImg || '')))
const videoSrc = computed(() => resolveMediaUrl(String(work.value?.videoUrl || work.value?.heroVideo || '')))
const descHtml = computed(() =>
  rewriteHtmlMediaUrls(String(work.value?.desc || work.value?.description || '')),
)
const techGroups = computed(() => {
  const stack = work.value?.techStack
  if (!Array.isArray(stack) || !stack.length) return []
  // 若已是分组且含 items，直接用；否则展平为单组
  if (stack.some(g => Array.isArray(g.items))) return stack
  const flat = flattenTechStack(stack)
  return flat.length ? [{ category: '技术栈', items: flat }] : []
})
const links = computed(() => parseWorkLinks(work.value?.links))
const gallery = computed(() => (work.value?.gallery || []).map(u => resolveMediaUrl(String(u))).filter(Boolean))
const meta = computed(() => [work.value?.year, work.value?.category].filter(Boolean).join(' · '))

/** 拉作品详情 */
async function loadDetail() {
  if (!workId.value) return
  loading.value = true
  try {
    work.value = await getWork(workId.value)
  }
  catch (e: unknown) {
    uni.showToast({ title: e instanceof Error ? e.message : '加载失败', icon: 'none' })
  }
  finally {
    loading.value = false
  }
}

onLoad((q) => {
  workId.value = String(q?.id || '')
  loadDetail()
})

onPullDownRefresh(async () => {
  try {
    await loadDetail()
  }
  finally {
    uni.stopPullDownRefresh()
  }
})

const playHero = () => {
  if (videoSrc.value) showVideo.value = true
}

const goNext = () => {
  if (!work.value?.next) return
  uni.redirectTo({ url: `/subPackages/content/pages/works/detail?id=${work.value.next}` })
}

const previewGallery = (current: string) => {
  uni.previewImage({ urls: gallery.value, current })
}
</script>

<template>
  <AppPageShell>
    <AppNavbar :title="work?.title || '作品详情'" show-back />
    <view v-if="work" class="page-pad animate-reveal">
      <view class="hero-wrap" @click="playHero">
        <image v-if="heroUrl" class="hero" :src="heroUrl" mode="aspectFill" />
        <view v-else class="hero hero--empty" />
        <view v-if="videoSrc" class="play-overlay">
          <wd-icon name="play-circle-fill" size="48px" color="#fff" />
        </view>
      </view>

      <video
        v-if="showVideo && videoSrc"
        class="player"
        :src="videoSrc"
        :poster="heroUrl"
        controls
        autoplay
        object-fit="contain"
      />

      <text v-if="meta" class="font-mono-label text-art-accent">{{ meta }}</text>
      <view class="section-title title">{{ work.title }}</view>

      <view v-if="descHtml" class="block">
        <text class="block-label font-mono-label text-art-muted">关于项目</text>
        <rich-text class="desc" :nodes="descHtml" />
      </view>

      <view v-if="techGroups.length" class="block">
        <text class="block-label font-mono-label text-art-muted">技术全景</text>
        <view v-for="(g, gi) in techGroups" :key="gi" class="tech-group">
          <text v-if="g.category" class="tech-cat text-art-accent">{{ g.category }}</text>
          <view class="pills">
            <text v-for="(t, ti) in (g.items || [])" :key="ti" class="pill">{{ t }}</text>
          </view>
        </view>
      </view>

      <view v-if="links.live || links.demo || links.github" class="block">
        <text class="block-label font-mono-label text-art-muted">相关链接</text>
        <view class="link-rows">
          <view v-if="links.live" class="link-row art-card" @click="openExternalUrl(links.live)">
            <wd-icon name="link" size="18px" color="rgb(212,179,131)" />
            <text>线上项目</text>
            <wd-icon name="arrow-right" size="14px" color="rgb(136,136,136)" />
          </view>
          <view v-if="links.demo" class="link-row art-card" @click="openExternalUrl(links.demo)">
            <wd-icon name="play-circle" size="18px" color="rgb(212,179,131)" />
            <text>演示</text>
            <wd-icon name="arrow-right" size="14px" color="rgb(136,136,136)" />
          </view>
          <view v-if="links.github" class="link-row art-card" @click="openExternalUrl(links.github)">
            <wd-icon name="code" size="18px" color="rgb(212,179,131)" />
            <text>源码</text>
            <wd-icon name="arrow-right" size="14px" color="rgb(136,136,136)" />
          </view>
        </view>
      </view>

      <view v-if="gallery.length" class="block">
        <text class="block-label font-mono-label text-art-muted">图集</text>
        <image
          v-for="(img, i) in gallery"
          :key="i"
          class="gallery-img"
          :class="i % 2 === 1 ? 'gallery-img--tall' : ''"
          :src="img"
          mode="aspectFill"
          @click="previewGallery(img)"
        />
      </view>

      <view v-if="work.next" class="next art-card art-card-press" @click="goNext">
        <text class="font-mono-label text-art-muted">下一个作品</text>
        <text class="next-cta text-art-accent">继续浏览 →</text>
      </view>
    </view>
    <wd-loading v-if="loading" />
  </AppPageShell>
</template>

<style scoped lang="scss">
.page-pad { padding: 24rpx 32rpx 100rpx; }
.hero-wrap { position: relative; margin-bottom: 28rpx; border-radius: 16rpx; overflow: hidden; }
.hero { width: 100%; height: 480rpx; display: block; }
.hero--empty { height: 480rpx; background: rgba(212, 179, 131, 0.12); }
.play-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.28);
}
.player {
  width: 100%;
  height: 420rpx;
  border-radius: 16rpx;
  background: #000;
  margin-bottom: 28rpx;
}
.title { margin: 12rpx 0 32rpx; }
.block { margin-bottom: 40rpx; }
.block-label { display: block; margin-bottom: 16rpx; }
.desc {
  font-size: 30rpx;
  line-height: 1.8;
  color: rgb(var(--art-text));
}
.tech-group { margin-bottom: 20rpx; }
.tech-cat { display: block; font-size: 24rpx; margin-bottom: 12rpx; }
.pills { display: flex; flex-wrap: wrap; gap: 12rpx; }
.pill {
  padding: 10rpx 18rpx;
  border: 1px solid var(--art-card-border);
  border-radius: 999rpx;
  font-size: 22rpx;
  color: rgb(var(--art-text));
}
.link-rows { display: flex; flex-direction: column; gap: 12rpx; }
.link-row {
  display: flex;
  align-items: center;
  gap: 16rpx;
  padding: 24rpx 28rpx;
  font-size: 28rpx;
  color: rgb(var(--art-text));
}
.link-row text { flex: 1; }
.gallery-img {
  width: 100%;
  height: 360rpx;
  border-radius: 12rpx;
  margin-bottom: 20rpx;
  display: block;
}
.gallery-img--tall { height: 480rpx; }
.next {
  margin-top: 16rpx;
  padding: 32rpx;
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.next-cta { font-size: 28rpx; }
</style>
