<template>
  <a-drawer
    v-model:open="visible"
    :title="drawerTitle"
    placement="right"
    width="600px"
    :footer="null"
    class="work-detail-drawer"
  >
    <a-spin :spinning="loading">
      <template v-if="workDetail">
        <!-- 提交时间 -->
        <div class="submit-time">
          {{ formatDateTime(workDetail.submitTime) }}
        </div>

        <!-- 作品介绍 -->
        <div class="section">
          <div class="section-title">作品介绍</div>
          <div class="section-content description">
            <template v-if="workDetail.description">
              <div v-html="workDetail.description"></div>
            </template>
            <span v-else class="empty-text">暂无介绍</span>
          </div>
        </div>

        <!-- 作品详情 - 预览图 -->
        <div class="section">
          <div class="section-title">作品详情</div>
          <div class="preview-container">
            <div class="preview-image" @mouseenter="showPreviewBtn = true" @mouseleave="showPreviewBtn = false">
              <img
                v-if="currentPreviewImageUrl"
                :src="currentPreviewImageUrl"
                alt="作品预览"
                @error="handleImageError"
              />
              <div v-else class="preview-placeholder">
                <FileImageOutlined />
                <span>暂无预览图</span>
              </div>
              <!-- 3D预览按钮 -->
              <transition name="fade">
                <div v-if="showPreviewBtn && hasModelFile" class="preview-btn-overlay" @click="handleView3DModel">
                  <a-button type="primary">
                    <template #icon><EyeOutlined /></template>
                    3D模型预览
                  </a-button>
                </div>
              </transition>
            </div>
            <div v-if="pageCount > 1" class="preview-pagination">
              <a-button type="link" :disabled="currentPageIndex === 0" @click="goPrevPage">上一页</a-button>
              <span class="page-indicator">{{ currentPageIndex + 1 }} / {{ pageCount }}</span>
              <a-button type="link" :disabled="currentPageIndex >= pageCount - 1" @click="goNextPage">
                下一页
              </a-button>
            </div>
            <div v-if="currentPageBodyText" class="preview-page-text">{{ currentPageBodyText }}</div>
            <!-- 配音：有单页 audioUrl 时展示；后续可在此扩展完整配音能力 -->
            <div v-if="currentPageAudioUrl" class="preview-page-voice">
              <audio :src="currentPageAudioUrl" controls preload="metadata" class="voice-audio" />
            </div>
          </div>
        </div>

        <!-- 作品附件 -->
        <div class="section">
          <div class="section-title">作品附件</div>
          <div class="attachments-list">
            <template v-if="workDetail.attachments && workDetail.attachments.length > 0">
              <div
                v-for="attachment in workDetail.attachments"
                :key="attachment.id"
                class="attachment-item"
              >
                <div class="attachment-name">
                  <span class="label">附件名称：</span>
                  <span>{{ attachment.fileName?.split('.')[0] || attachment.fileName }}</span>
                </div>
                <div class="attachment-file">
                  <PaperClipOutlined class="file-icon" />
                  <span class="file-name">{{ attachment.fileName }}</span>
                  <a-button
                    type="link"
                    size="small"
                    @click="handleDownload(attachment)"
                  >
                    <template #icon><DownloadOutlined /></template>
                  </a-button>
                </div>
              </div>
            </template>
            <a-empty v-else description="暂无附件" :image="false" />
          </div>
        </div>

        <!-- 评审记录：纵向卡片，避免多评委时 Tab 横向溢出 -->
        <div class="section section-review">
          <div class="section-title">评审记录</div>
          <div class="review-records">
            <template v-if="reviewRecords && reviewRecords.length > 0">
              <div
                v-for="(record, index) in reviewRecords"
                :key="record.scoreId ?? record.id ?? index"
                class="review-judge-block"
              >
                <div class="review-judge-header">
                  <span class="review-judge-title">{{ judgeDisplayName(record, index) }}</span>
                </div>
                <div class="review-card">
                  <div class="review-item">
                    <span class="review-label">作品评分：</span>
                    <span v-if="record.totalScore !== null && record.totalScore !== undefined" class="review-score">
                      {{ record.totalScore }} 分
                    </span>
                    <span v-else class="not-reviewed">未评审</span>
                  </div>
                  <div class="review-item">
                    <span class="review-label">评委老师：</span>
                    <span class="review-value">{{ judgeNameText(record) || '-' }}</span>
                  </div>
                  <div class="review-item">
                    <span class="review-label">评分时间：</span>
                    <span class="review-value">
                      {{ record.scoreTime ? formatDateTime(record.scoreTime) : '-' }}
                    </span>
                  </div>
                  <div v-if="record.comments" class="review-item comment">
                    <span class="review-label">老师评语：</span>
                    <span class="review-value">{{ record.comments }}</span>
                  </div>
                </div>
              </div>
            </template>
            <a-empty v-else description="暂无评审记录" :image="false" />
          </div>
        </div>
      </template>
      <a-empty v-else-if="!loading" description="暂无数据" />
    </a-spin>
  </a-drawer>
</template>

<script setup lang="ts">
import { ref, watch, computed } from "vue"
import { useRoute, useRouter } from "vue-router"
import { message } from "ant-design-vue"
import {
  FileImageOutlined,
  EyeOutlined,
  PaperClipOutlined,
  DownloadOutlined
} from "@ant-design/icons-vue"
import dayjs from "dayjs"
import { worksApi, reviewsApi, type ContestWork } from "@/api/contests"
import {
  buildContestWorkPreviewPages,
  isContestWorkModelFile,
  normalizeContestWorkAssetUrl
} from "@/composables/useContestWorkPreviewPages"

interface Props {
  open: boolean
  workId?: number | null
}

const props = defineProps<Props>()
const emit = defineEmits<{
  "update:open": [value: boolean]
}>()

const route = useRoute()
const router = useRouter()

// 弹框显示状态
const visible = ref(false)
const loading = ref(false)
const workDetail = ref<ContestWork | null>(null)
const reviewRecords = ref<any[]>([])
const showPreviewBtn = ref(false)
const currentPageIndex = ref(0)

/** 评委展示名：接口扁平字段 judgeName，或嵌套 judge（与列表接口一致） */
const judgeNameText = (record: any) => {
  const flat = record?.judgeName
  if (flat != null && String(flat).trim() !== '') return String(flat).trim()
  return (
    record?.judge?.nickname ||
    record?.judge?.username ||
    ''
  )
}

/** 纵向列表标题：有姓名用姓名，否则「评委一、评委二…」 */
const judgeDisplayName = (record: any, index: number) => {
  const name = judgeNameText(record)
  if (name) return name
  const numerals = ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十']
  const n = index + 1
  if (n >= 1 && n <= 10) return `评委${numerals[n - 1]}`
  return `评委 ${n}`
}

// 抽屉标题
const drawerTitle = computed(() => {
  if (workDetail.value) {
    const workNo = workDetail.value.workNo || ""
    const title = workDetail.value.title || ""
    return workNo && title ? `${workNo} ${title}` : workNo || title || "作品详情"
  }
  return "作品详情"
})

/** 绘本多页 + 3D 模型 URL 统一解析 */
const previewResult = computed(() => buildContestWorkPreviewPages(workDetail.value))

const previewPages = computed(() => previewResult.value.pages)
const pageCount = computed(() => previewPages.value.length)

const currentPreviewImageUrl = computed(() => {
  const pages = previewPages.value
  if (pages.length === 0) return ""
  const idx = Math.min(currentPageIndex.value, pages.length - 1)
  return pages[idx]?.imageUrl || ""
})

const currentPageBodyText = computed(() => {
  const pages = previewPages.value
  if (pages.length === 0) return ""
  const idx = Math.min(currentPageIndex.value, pages.length - 1)
  const t = pages[idx]?.text
  return t && String(t).trim() ? String(t).trim() : ""
})

const currentPageAudioUrl = computed(() => {
  const pages = previewPages.value
  if (pages.length === 0) return ""
  const idx = Math.min(currentPageIndex.value, pages.length - 1)
  return pages[idx]?.audioUrl || ""
})

/** 用于 3D 查看器：优先 composable 解析的模型 URL，否则附件中的模型 */
const allModelUrlsForViewer = computed(() => {
  const fromWork = previewResult.value.modelFileUrls
  if (fromWork.length > 0) return fromWork
  const att = workDetail.value?.attachments
  if (!att?.length) return []
  return att
    .filter(
      (a) =>
        isContestWorkModelFile(a.fileName || "") || isContestWorkModelFile(a.fileUrl || "")
    )
    .map((a) => normalizeContestWorkAssetUrl(a.fileUrl || ""))
    .filter(Boolean)
})

// 是否有3D模型文件
const hasModelFile = computed(() => allModelUrlsForViewer.value.length > 0)

// 获取3D模型文件URL（首项）
const modelFileUrl = computed(() => allModelUrlsForViewer.value[0] || "")

const goPrevPage = () => {
  if (currentPageIndex.value > 0) currentPageIndex.value -= 1
}

const goNextPage = () => {
  if (currentPageIndex.value < pageCount.value - 1) currentPageIndex.value += 1
}

// 格式化日期时间
const formatDateTime = (dateStr?: string) => {
  if (!dateStr) return "-"
  return dayjs(dateStr).format("YYYY.MM.DD  HH:mm")
}

// 获取作品详情
const fetchWorkDetail = async (id: number) => {
  loading.value = true
  try {
    const detail = await worksApi.getDetail(id)
    workDetail.value = detail
    currentPageIndex.value = 0
    // 获取评审记录
    await fetchReviewRecords(id)
  } catch (error: any) {
    message.error(error?.response?.data?.message || "获取作品详情失败")
    workDetail.value = null
  } finally {
    loading.value = false
  }
}

// 获取评审记录
const fetchReviewRecords = async (workId: number) => {
  try {
    const records = await reviewsApi.getWorkScores(workId)
    reviewRecords.value = records || []
  } catch (error) {
    console.error("获取评审记录失败", error)
    reviewRecords.value = []
  }
}

// 处理图片加载错误
const handleImageError = (e: Event) => {
  const target = e.target as HTMLImageElement
  target.style.display = "none"
}

// 跳转3D模型预览
const handleView3DModel = () => {
  const tenantCode = route.params.tenantCode as string
  const allModelUrls = allModelUrlsForViewer.value
  const primary = allModelUrls[0] || modelFileUrl.value
  if (primary) {
    if (allModelUrls.length > 1) {
      sessionStorage.setItem("model-viewer-urls", JSON.stringify(allModelUrls))
      sessionStorage.setItem("model-viewer-index", "0")
      sessionStorage.removeItem("model-viewer-url")
    } else {
      sessionStorage.setItem("model-viewer-url", primary)
      sessionStorage.removeItem("model-viewer-urls")
      sessionStorage.removeItem("model-viewer-index")
    }
    router.push({
      path: `/${tenantCode}/workbench/model-viewer`,
    })
  } else {
    message.warning("未找到3D模型文件")
  }
}

// 下载附件
const handleDownload = (attachment: any) => {
  if (attachment.fileUrl) {
    window.open(attachment.fileUrl, "_blank")
  }
}

// 监听 open 属性变化
watch(
  () => props.open,
  (newVal) => {
    visible.value = newVal
    if (newVal && props.workId) {
      fetchWorkDetail(props.workId)
    } else if (!newVal) {
      workDetail.value = null
      reviewRecords.value = []
    }
  }
)

// 监听 visible 变化同步到父组件
watch(visible, (newVal) => {
  emit("update:open", newVal)
})

// 监听 workId 变化
watch(
  () => props.workId,
  (newVal) => {
    if (newVal && props.open) {
      fetchWorkDetail(newVal)
    }
  }
)
</script>

<style scoped lang="scss">
.work-detail-drawer {
  :deep(.ant-drawer-body) {
    padding: 16px 24px;
    overflow-x: hidden;
    max-width: 100%;
    box-sizing: border-box;
  }
}

.submit-time {
  color: #666;
  font-size: 14px;
  margin-bottom: 20px;
}

.section {
  margin-bottom: 24px;

  .section-title {
    font-size: 15px;
    font-weight: 500;
    color: #333;
    margin-bottom: 12px;
  }

  .section-content {
    color: #666;
    font-size: 14px;
    line-height: 1.8;
  }

  .description {
    background: #fafafa;
    padding: 12px 16px;
    border-radius: 6px;
  }

  .empty-text {
    color: #999;
  }
}

.preview-pagination {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  margin-top: 12px;

  .page-indicator {
    color: #666;
    font-size: 14px;
    min-width: 52px;
    text-align: center;
  }

  :deep(.ant-btn-link) {
    color: #0958d9;
    padding: 0 4px;

    &:disabled {
      color: #bfbfbf;
    }
  }
}

.preview-page-text {
  margin-top: 12px;
  padding: 12px 16px;
  background: #fafafa;
  border-radius: 6px;
  color: #333;
  font-size: 14px;
  line-height: 1.7;
  white-space: pre-wrap;
  word-break: break-word;
}

.preview-page-voice {
  margin-top: 10px;

  .voice-audio {
    width: 100%;
    max-height: 48px;
  }
}

.preview-container {
  .preview-image {
    position: relative;
    width: 100%;
    height: 280px;
    background: #f5f5f5;
    border-radius: 8px;
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;

    img {
      max-width: 100%;
      max-height: 100%;
      object-fit: contain;
    }

    .preview-placeholder {
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      color: #bbb;
      font-size: 14px;

      :deep(.anticon) {
        font-size: 48px;
        margin-bottom: 12px;
      }
    }

    .preview-btn-overlay {
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      background: rgba(0, 0, 0, 0.5);
      display: flex;
      align-items: center;
      justify-content: center;
      cursor: pointer;
    }
  }
}

.attachments-list {
  .attachment-item {
    margin-bottom: 16px;

    &:last-child {
      margin-bottom: 0;
    }

    .attachment-name {
      margin-bottom: 8px;
      font-size: 14px;

      .label {
        color: #0958d9;
      }
    }

    .attachment-file {
      display: flex;
      align-items: center;
      padding: 8px 12px;
      background: #fafafa;
      border-radius: 6px;

      .file-icon {
        color: #52c41a;
        margin-right: 8px;
      }

      .file-name {
        flex: 1;
        color: #333;
        font-size: 14px;
      }
    }
  }
}

.section-review {
  min-width: 0;
}

.review-records {
  min-width: 0;
  width: 100%;

  .review-judge-block {
    margin-bottom: 16px;

    &:last-child {
      margin-bottom: 0;
    }
  }

  .review-judge-header {
    margin-bottom: 8px;
  }

  .review-judge-title {
    font-size: 14px;
    font-weight: 600;
    color: #1f2937;
    word-break: break-all;
  }

  .review-card {
    background: #fff;
    border-left: 3px solid #52c41a;
    padding: 16px;
    border-radius: 0 8px 8px 0;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
    max-width: 100%;
    box-sizing: border-box;

    .review-item {
      margin-bottom: 12px;
      font-size: 14px;
      line-height: 1.6;
      word-break: break-word;
      overflow-wrap: anywhere;

      &:last-child {
        margin-bottom: 0;
      }

      .review-label {
        color: #666;
        flex-shrink: 0;
      }

      .review-value {
        color: #333;
      }

      .review-score {
        color: #0958d9;
        font-size: 18px;
        font-weight: 600;
      }

      .not-reviewed {
        color: #999;
      }

      &.comment {
        .review-value {
          color: #52c41a;
        }
      }
    }
  }
}

.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.2s ease;
}

.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}
</style>
