<!--
  会议录制列表 + 回放页（Phase B）

  路由：/pages/meeting/recordings?code=<room_code>
  - 通过 query.code 拉取该房间的录制历史
  - 仅会议参与者（包括 host）可访问；后端 listRecordings 会做鉴权
  - 列表按开始时间倒序；每条展示 状态徽章 / 时长 / 大小 / 操作按钮
  - status=ready 时可在线播放（H5 用 <video>）或下载；其他状态禁用回放
-->
<template>
  <view class="recordings">
    <view class="header">
      <text class="room-code">会议号 {{ roomCode || '—' }}</text>
      <button class="refresh-btn" :disabled="loading" @click="loadList">刷新</button>
    </view>

    <view v-if="loading && list.length === 0" class="empty-state">
      <text>加载中…</text>
    </view>

    <view v-else-if="list.length === 0" class="empty-state">
      <text>{{ errorMsg || '该会议暂无录制' }}</text>
    </view>

    <view v-else class="rec-list">
      <view
        v-for="item in list"
        :key="item.id"
        class="rec-card"
        :class="{ active: playingId === item.id }"
      >
        <view class="rec-meta">
          <view class="rec-row">
            <view class="status-pill" :class="`status-${item.status}`">
              {{ statusLabel(item.status) }}
            </view>
            <text class="rec-time">{{ formatStartTime(item.started_at) }}</text>
          </view>
          <view class="rec-row">
            <text class="rec-info">时长 {{ formatDuration(item.duration_sec) }}</text>
            <text class="rec-info">大小 {{ formatBytes(item.size_bytes) }}</text>
          </view>
          <view v-if="item.status === 'failed' && item.failure_reason" class="rec-failure">
            失败原因：{{ item.failure_reason }}
          </view>
        </view>
        <view class="rec-actions">
          <button
            v-if="item.status === 'ready' && item.file_url"
            class="action-btn primary"
            @click="togglePlay(item)"
          >
            {{ playingId === item.id ? '收起' : '播放' }}
          </button>
          <button
            v-if="item.status === 'ready' && item.file_url"
            class="action-btn"
            @click="copyLink(item)"
          >
            复制链接
          </button>
        </view>
        <!-- 内联播放器：仅 H5 用 <video>；其他平台跳系统播放器 -->
        <!-- #ifdef H5 -->
        <view v-if="playingId === item.id && item.file_url" class="rec-player">
          <video :src="item.file_url" controls autoplay class="player-el"></video>
        </view>
        <!-- #endif -->
      </view>
    </view>
  </view>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import meetingApi from '@/api/meeting'
import {
  MEETING_RECORDING_STATUS_LABEL
} from '@/constants/meeting'

const roomCode = ref('')
const list = ref([])
const loading = ref(false)
const errorMsg = ref('')
const playingId = ref(null)

const statusLabel = (s) => MEETING_RECORDING_STATUS_LABEL[s] || s || '—'

const formatStartTime = (unix) => {
  if (!unix) return '—'
  const d = new Date(unix * 1000)
  const pad = (n) => String(n).padStart(2, '0')
  return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`
}

const formatDuration = (sec) => {
  if (!sec || sec <= 0) return '—'
  const h = Math.floor(sec / 3600)
  const m = Math.floor((sec % 3600) / 60)
  const s = sec % 60
  if (h > 0) return `${h}h ${m}m ${s}s`
  if (m > 0) return `${m}m ${s}s`
  return `${s}s`
}

const formatBytes = (b) => {
  if (!b || b <= 0) return '—'
  const units = ['B', 'KB', 'MB', 'GB']
  let n = b
  let i = 0
  while (n >= 1024 && i < units.length - 1) {
    n /= 1024
    i++
  }
  return `${n.toFixed(n >= 100 ? 0 : 1)} ${units[i]}`
}

const loadList = async () => {
  if (!roomCode.value) {
    errorMsg.value = '缺少会议号参数'
    return
  }
  loading.value = true
  errorMsg.value = ''
  try {
    const resp = await meetingApi.listRecordings(roomCode.value)
    // 后端返回 { list: [...] }
    const arr = Array.isArray(resp?.list) ? resp.list : []
    // 按 started_at 倒序，最新优先
    arr.sort((a, b) => (b.started_at || 0) - (a.started_at || 0))
    list.value = arr
  } catch (err) {
    errorMsg.value = err?.message || '加载失败'
    uni.showToast({ title: errorMsg.value, icon: 'none' })
  } finally {
    loading.value = false
  }
}

const togglePlay = (item) => {
  if (playingId.value === item.id) {
    playingId.value = null
    return
  }
  playingId.value = item.id
  // #ifndef H5
  // 非 H5 平台直接跳系统播放器
  uni.navigateTo({
    url: `/pages/common/video-player?src=${encodeURIComponent(item.file_url)}`
  }).catch(() => {
    // 兜底：未注册 video-player 页，用系统打开
    plus?.runtime?.openURL?.(item.file_url)
  })
  // #endif
}

const copyLink = (item) => {
  uni.setClipboardData({
    data: item.file_url,
    success: () => uni.showToast({ title: '链接已复制', icon: 'success' })
  })
}

onLoad((query) => {
  roomCode.value = (query?.code || '').toString()
})

onMounted(() => {
  if (roomCode.value) {
    loadList()
  }
})
</script>

<style scoped>
.recordings {
  min-height: 100vh;
  background: #F9FAFB;
  padding: 24rpx;
  box-sizing: border-box;
}

.header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 24rpx;
}
.room-code {
  font-size: 32rpx;
  font-weight: 600;
  color: #111827;
}
.refresh-btn {
  font-size: 26rpx;
  padding: 8rpx 24rpx;
  border-radius: 999rpx;
  background: #3B82F6;
  color: #FFFFFF;
  border: none;
}
.refresh-btn[disabled] { opacity: 0.5; }

.empty-state {
  padding: 120rpx 0;
  text-align: center;
  color: #6B7280;
  font-size: 28rpx;
}

.rec-list {
  display: flex;
  flex-direction: column;
  gap: 16rpx;
}
.rec-card {
  background: #FFFFFF;
  border: 1rpx solid #E5E7EB;
  border-radius: 16rpx;
  padding: 24rpx;
  box-shadow: 0 1rpx 2rpx rgba(0, 0, 0, 0.04);
  transition: border-color 0.2s ease;
}
.rec-card.active { border-color: #3B82F6; }

.rec-meta { display: flex; flex-direction: column; gap: 8rpx; }
.rec-row { display: flex; align-items: center; gap: 16rpx; flex-wrap: wrap; }
.rec-time { font-size: 26rpx; color: #374151; font-weight: 500; }
.rec-info { font-size: 24rpx; color: #6B7280; }
.rec-failure {
  font-size: 22rpx;
  color: #DC2626;
  margin-top: 6rpx;
}

.status-pill {
  display: inline-flex;
  align-items: center;
  font-size: 22rpx;
  padding: 4rpx 14rpx;
  border-radius: 999rpx;
  font-weight: 500;
}
.status-recording { background: #FEE2E2; color: #DC2626; }
.status-uploading { background: #FEF3C7; color: #B45309; }
.status-ready     { background: #D1FAE5; color: #065F46; }
.status-failed    { background: #E5E7EB; color: #6B7280; }

.rec-actions {
  display: flex;
  gap: 12rpx;
  margin-top: 16rpx;
}
.action-btn {
  font-size: 24rpx;
  padding: 8rpx 24rpx;
  border-radius: 8rpx;
  background: #F3F4F6;
  color: #374151;
  border: 1rpx solid #E5E7EB;
}
.action-btn.primary {
  background: #3B82F6;
  color: #FFFFFF;
  border-color: #3B82F6;
}

.rec-player { margin-top: 16rpx; }
.player-el { width: 100%; max-height: 480rpx; border-radius: 12rpx; background: #000; }
</style>
