<script setup lang="ts">
import { ref, onUnmounted } from 'vue'

const GATEWAY_URL = 'http://localhost:8080'

// 查询参数
const channelId = ref(1)
const startTime = ref('')
const endTime = ref('')
const queryLoading = ref(false)
const queryError = ref('')
const recordList = ref<any[]>([])
const selectedRecord = ref<any>(null)

// 初始化时间为今天全天
const initTime = () => {
  const today = new Date()
  const year = today.getFullYear()
  const month = String(today.getMonth() + 1).padStart(2, '0')
  const day = String(today.getDate()).padStart(2, '0')

  startTime.value = `${year}-${month}-${day} 00:00:00`
  endTime.value = `${year}-${month}-${day} 23:59:59`
}

// 初始化时间
initTime()

// 查询录像列表
const queryRecordList = async () => {
  if (!channelId.value) {
    queryError.value = '请输入通道ID'
    return
  }

  if (!startTime.value || !endTime.value) {
    queryError.value = '请选择开始时间和结束时间'
    return
  }

  queryLoading.value = true
  queryError.value = ''
  recordList.value = []
  selectedRecord.value = null

  try {
    const params = new URLSearchParams({
      channelId: channelId.value.toString(),
      startTime: startTime.value,
      endTime: endTime.value
    })

    const response = await fetch(`${GATEWAY_URL}/wvp/api/common/channel/playback/query?${params}`)

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`)
    }

    const data = await response.json()
    if (data.code === 0 && data.data) {
      recordList.value = data.data
      if (recordList.value.length === 0) {
        queryError.value = '未找到录像记录'
      }
    } else {
      queryError.value = data.msg || '查询录像列表失败'
    }
  } catch (error) {
    queryError.value = error instanceof Error ? error.message : '查询录像列表失败'
  } finally {
    queryLoading.value = false
  }
}

// 播放相关
const playLoading = ref(false)
const playError = ref('')
const playbackData = ref<any>(null)
const currentStreamId = ref<string>('')

// Jessibuca 播放器
let jessibucaPlayer: any = null
const playerContainerRef = ref<HTMLDivElement | null>(null)
const isPlaying = ref(false)
const kBps = ref(0)

// 停止当前播放流（调用API）
const stopPlaybackStream = async () => {
  if (!currentStreamId.value) {
    return
  }

  try {
    const params = new URLSearchParams({
      channelId: channelId.value.toString(),
      stream: currentStreamId.value
    })

    const response = await fetch(`${GATEWAY_URL}/wvp/api/common/channel/playback/stop?${params}`)

    if (!response.ok) {
      console.error('停止播放流失败:', response.status)
    }

    const data = await response.json()
    if (data.code === 0) {
      console.log('停止播放流成功')
    } else {
      console.error('停止播放流失败:', data.msg)
    }
  } catch (error) {
    console.error('停止播放流异常:', error)
  } finally {
    currentStreamId.value = ''
  }
}

// 播放录像
const playRecord = async (record: any) => {
  selectedRecord.value = record
  playLoading.value = true
  playError.value = ''

  // 先停止当前播放的流（如果有）
  if (currentStreamId.value) {
    await stopPlaybackStream()
  }

  // 停止播放器
  stopPlay()

  try {
    const params = new URLSearchParams({
      channelId: channelId.value.toString(),
      startTime: record.startTime,
      endTime: record.endTime
    })

    const response = await fetch(`${GATEWAY_URL}/wvp/api/common/channel/playback?${params}`)

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`)
    }

    const data = await response.json()
    if (data.code === 0 && data.data) {
      playbackData.value = data.data
      playError.value = ''

      // 保存stream ID用于后续停止
      if (data.data.stream) {
        currentStreamId.value = data.data.stream
      }

      // 自动播放WebSocket-FLV流
      const playUrl = getPlayUrl(data.data)
      if (playUrl) {
        setTimeout(() => {
          playJessibuca(playUrl)
        }, 500)
      } else {
        playError.value = '未找到可用的播放地址'
      }
    } else {
      playError.value = data.msg || '获取播放地址失败'
    }
  } catch (error) {
    playError.value = error instanceof Error ? error.message : '获取播放地址失败'
  } finally {
    playLoading.value = false
  }
}

// 获取播放地址（优先使用WebSocket-FLV）
const getPlayUrl = (data: any) => {
  // 根据协议选择合适的流地址
  if (location.protocol === 'https:') {
    return data.wss_flv || data.ws_flv || data.flv
  } else {
    return data.ws_flv || data.wss_flv || data.flv
  }
}

// 使用Jessibuca播放器播放
const playJessibuca = (url: string) => {
  playError.value = ''

  if (!playerContainerRef.value) {
    playError.value = '播放器容器未找到'
    return
  }

  if (jessibucaPlayer) {
    jessibucaPlayer.destroy()
    jessibucaPlayer = null
  }

  try {
    // @ts-ignore
    jessibucaPlayer = new window.Jessibuca({
      container: playerContainerRef.value,
      videoBuffer: 0,
      isResize: true,
      useMSE: true,
      useWCS: false,
      text: '',
      controlAutoHide: false,
      debug: false,
      hotKey: true,
      // @ts-ignore
      decoder: '/static/js/jessibuca/decoder.js',
      timeout: 10,
      recordType: 'mp4',
      isFlv: false,
      forceNoOffscreen: true,
      hasAudio: true,
      heartTimeout: 5,
      heartTimeoutReplay: true,
      heartTimeoutReplayTimes: 3,
      hiddenAutoPause: false,
      isNotMute: true,
      keepScreenOn: true,
      loadingText: '请稍等, 视频加载中......',
      loadingTimeout: 10,
      loadingTimeoutReplay: true,
      loadingTimeoutReplayTimes: 3,
      operateBtns: {
        fullscreen: false,
        screenshot: false,
        play: false,
        audio: false,
        recorder: false
      },
      showBandwidth: false,
      supportDblclickFullscreen: false,
      useWebFullSreen: true,
      wasmDecodeErrorReplay: true
    })

    jessibucaPlayer.on('play', () => {
      isPlaying.value = true
    })

    jessibucaPlayer.on('pause', () => {
      isPlaying.value = false
    })

    jessibucaPlayer.on('kBps', (val: number) => {
      kBps.value = Math.round(val)
    })

    jessibucaPlayer.on('error', (error: any) => {
      console.error('Jessibuca error:', error)
      playError.value = '播放错误: ' + (error.message || error)
      isPlaying.value = false
    })

    jessibucaPlayer.on('timeout', () => {
      playError.value = '播放超时'
      isPlaying.value = false
    })

    jessibucaPlayer.play(url)
  } catch (error) {
    playError.value = error instanceof Error ? error.message : '播放失败'
    isPlaying.value = false
  }
}

// 停止播放（仅停止播放器，不调用API）
const stopPlay = () => {
  if (jessibucaPlayer) {
    jessibucaPlayer.pause()
    jessibucaPlayer.destroy()
    jessibucaPlayer = null
  }
  isPlaying.value = false
  kBps.value = 0
}

// 完全停止播放（停止播放器并调用API）
const stopPlayComplete = async () => {
  // 停止播放器
  stopPlay()

  // 调用API停止流
  await stopPlaybackStream()

  // 清空播放数据
  playbackData.value = null
  selectedRecord.value = null
}

// 格式化文件大小
const formatFileSize = (size: number | null) => {
  if (!size) return '-'
  if (size < 1024) return size + ' B'
  if (size < 1024 * 1024) return (size / 1024).toFixed(2) + ' KB'
  if (size < 1024 * 1024 * 1024) return (size / 1024 / 1024).toFixed(2) + ' MB'
  return (size / 1024 / 1024 / 1024).toFixed(2) + ' GB'
}

// 组件卸载时清理播放器和停止流
onUnmounted(async () => {
  stopPlay()
  await stopPlaybackStream()
})
</script>

<template>
  <div class="gb28181-record-container">
    <h2>GB28181 国标录像回放</h2>

    <div class="api-section">
      <h3>1. 查询录像列表</h3>
      <div class="api-description">
        <p>通过网关调用: <code>GET /wvp/api/common/channel/playback/query</code></p>
        <p>实际转发到: <code>http://114.67.89.4:9090/api/common/channel/playback/query</code></p>
        <p>网关会自动注入 access-token 请求头</p>
      </div>

      <div class="form-group">
        <label>通道ID (channelId) - 必填:</label>
        <input
          v-model.number="channelId"
          type="number"
          min="1"
          placeholder="请输入通道ID"
        />
        <small style="color: #666; display: block; margin-top: 5px;">
          提示：通道ID是数据库主键ID（gbId），不是国标设备ID
        </small>
      </div>

      <div class="form-row">
        <div class="form-group">
          <label>开始时间 (startTime):</label>
          <input
            v-model="startTime"
            type="text"
            placeholder="2025-12-10 00:00:00"
          />
        </div>

        <div class="form-group">
          <label>结束时间 (endTime):</label>
          <input
            v-model="endTime"
            type="text"
            placeholder="2025-12-10 23:59:59"
          />
        </div>
      </div>

      <div class="button-group">
        <button @click="queryRecordList" :disabled="queryLoading">
          {{ queryLoading ? '查询中...' : '搜索' }}
        </button>
        <button @click="initTime" class="secondary-button">
          重置为今天
        </button>
      </div>

      <div v-if="queryError" class="error">
        错误: {{ queryError }}
      </div>

      <div v-if="recordList.length > 0" class="record-list">
        <h4>录像列表 (共 {{ recordList.length }} 条):</h4>
        <table class="record-table">
          <thead>
            <tr>
              <th>序号</th>
              <th>开始时间</th>
              <th>结束时间</th>
              <th>文件大小</th>
              <th>操作</th>
            </tr>
          </thead>
          <tbody>
            <tr
              v-for="(record, index) in recordList"
              :key="index"
              :class="{ 'selected': selectedRecord === record }"
            >
              <td>{{ index + 1 }}</td>
              <td>{{ record.startTime }}</td>
              <td>{{ record.endTime }}</td>
              <td>{{ formatFileSize(record.fileSize) }}</td>
              <td>
                <button
                  @click="playRecord(record)"
                  class="play-button"
                  :disabled="playLoading && selectedRecord === record"
                >
                  {{ (playLoading && selectedRecord === record) ? '加载中...' : '播放' }}
                </button>
              </td>
            </tr>
          </tbody>
        </table>
      </div>
    </div>

    <div class="api-section" v-if="playbackData">
      <h3>2. 录像回放</h3>
      <div class="api-description">
        <p>播放接口: <code>GET /wvp/api/common/channel/playback</code></p>
        <p>实际转发到: <code>http://114.67.89.4:9090/api/common/channel/playback</code></p>
      </div>

      <div class="selected-record-info">
        <h4>当前播放的录像:</h4>
        <p><strong>开始时间:</strong> {{ selectedRecord?.startTime }}</p>
        <p><strong>结束时间:</strong> {{ selectedRecord?.endTime }}</p>
        <p><strong>文件大小:</strong> {{ formatFileSize(selectedRecord?.fileSize) }}</p>
      </div>

      <div class="player-section">
        <h4>视频播放器 (Jessibuca):</h4>
        <div class="video-container">
          <div
            ref="playerContainerRef"
            class="video-player"
            style="width: 100%; height: 100%; background-color: #000; position: relative;"
          ></div>
        </div>

        <div class="player-info" v-if="isPlaying">
          <span class="info-text">播放中</span>
          <span class="info-text" style="margin-left: 20px;">码率: {{ kBps }} kb/s</span>
        </div>

        <div class="button-group">
          <button @click="stopPlayComplete" :disabled="!isPlaying" class="stop-button">
            停止播放
          </button>
        </div>

        <div v-if="playError" class="error">
          播放错误: {{ playError }}
        </div>
      </div>

      <div class="play-urls-info">
        <h4>播放地址:</h4>
        <div class="url-list">
          <div v-if="playbackData.ws_flv" class="url-item">
            <strong>WebSocket-FLV:</strong>
            <code>{{ playbackData.ws_flv }}</code>
            <button @click="playJessibuca(playbackData.ws_flv)" class="small-button">播放</button>
          </div>
          <div v-if="playbackData.wss_flv" class="url-item">
            <strong>WebSocket-FLV (SSL):</strong>
            <code>{{ playbackData.wss_flv }}</code>
            <button @click="playJessibuca(playbackData.wss_flv)" class="small-button">播放</button>
          </div>
          <div v-if="playbackData.flv" class="url-item">
            <strong>HTTP-FLV:</strong>
            <code>{{ playbackData.flv }}</code>
          </div>
          <div v-if="playbackData.hls" class="url-item">
            <strong>HLS:</strong>
            <code>{{ playbackData.hls }}</code>
          </div>
          <div v-if="playbackData.rtmp" class="url-item">
            <strong>RTMP:</strong>
            <code>{{ playbackData.rtmp }}</code>
          </div>
          <div v-if="playbackData.rtsp" class="url-item">
            <strong>RTSP:</strong>
            <code>{{ playbackData.rtsp }}</code>
          </div>
          <div v-if="playbackData.rtc" class="url-item">
            <strong>WebRTC:</strong>
            <code>{{ playbackData.rtc }}</code>
          </div>
        </div>
      </div>
    </div>

    <div class="info-box">
      <h4>使用说明:</h4>
      <p>1. 输入通道ID（数据库主键ID，不是国标设备ID）</p>
      <p>2. 选择开始时间和结束时间，默认为今天全天</p>
      <p>3. 点击"搜索"按钮查询录像列表</p>
      <p>4. 在录像列表中点击"播放"按钮播放对应的录像</p>
      <p>5. 录像会使用Jessibuca播放器自动播放WebSocket-FLV流</p>
      <p><strong>注意:</strong> 时间格式为 YYYY-MM-DD HH:mm:ss，例如：2025-12-10 00:00:00</p>
      <p><strong>播放器:</strong> 使用Jessibuca播放器，支持WebSocket-FLV协议，低延迟高性能</p>
    </div>
  </div>
</template>

<style scoped>
.gb28181-record-container {
  max-width: 1200px;
  margin: 0 auto;
  padding: 20px;
}

h2 {
  margin-bottom: 30px;
  color: #333;
}

.api-section {
  background-color: #fff;
  border: 1px solid #e0e0e0;
  border-radius: 8px;
  padding: 20px;
  margin-bottom: 20px;
}

.api-section h3 {
  margin-top: 0;
  margin-bottom: 15px;
  color: #2196f3;
  font-size: 18px;
}

.api-description {
  background-color: #f5f5f5;
  padding: 12px;
  border-radius: 4px;
  margin-bottom: 20px;
}

.api-description p {
  margin: 5px 0;
  font-size: 14px;
  color: #666;
}

.api-description code {
  background-color: #e0e0e0;
  padding: 2px 6px;
  border-radius: 3px;
  font-family: 'Courier New', monospace;
  font-size: 13px;
  color: #d32f2f;
}

.form-group {
  margin-bottom: 15px;
}

.form-group label {
  display: block;
  margin-bottom: 5px;
  font-weight: 500;
  color: #333;
  font-size: 14px;
}

.form-group input[type="text"],
.form-group input[type="number"] {
  width: 100%;
  padding: 8px 12px;
  border: 1px solid #ddd;
  border-radius: 4px;
  font-size: 14px;
  box-sizing: border-box;
}

.form-group input:focus {
  outline: none;
  border-color: #2196f3;
}

.form-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 15px;
}

.button-group {
  display: flex;
  gap: 10px;
  margin-top: 20px;
}

button {
  padding: 10px 20px;
  background-color: #2196f3;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 14px;
  font-weight: 500;
  transition: background-color 0.3s ease;
}

button:hover:not(:disabled) {
  background-color: #1976d2;
}

button:disabled {
  background-color: #ccc;
  cursor: not-allowed;
}

.secondary-button {
  background-color: #757575;
}

.secondary-button:hover:not(:disabled) {
  background-color: #616161;
}

.stop-button {
  background-color: #f44336;
}

.stop-button:hover:not(:disabled) {
  background-color: #d32f2f;
}

.play-button {
  padding: 5px 15px;
  font-size: 12px;
}

.small-button {
  padding: 5px 10px;
  font-size: 12px;
  margin-left: 10px;
}

.error {
  margin-top: 15px;
  padding: 12px;
  background-color: #ffebee;
  color: #c62828;
  border-radius: 4px;
  font-size: 14px;
}

.record-list {
  margin-top: 20px;
}

.record-list h4 {
  margin-bottom: 10px;
  color: #333;
}

.record-table {
  width: 100%;
  border-collapse: collapse;
  background-color: white;
  border-radius: 4px;
  overflow: hidden;
  border: 1px solid #e0e0e0;
}

.record-table thead {
  background-color: #2196f3;
  color: white;
}

.record-table th,
.record-table td {
  padding: 12px;
  text-align: left;
  border-bottom: 1px solid #e0e0e0;
}

.record-table th {
  font-weight: 600;
  font-size: 14px;
}

.record-table td {
  font-size: 13px;
  color: #333;
}

.record-table tbody tr:hover {
  background-color: #f5f5f5;
}

.record-table tbody tr.selected {
  background-color: #e3f2fd;
}

.record-table tbody tr:last-child td {
  border-bottom: none;
}

.selected-record-info {
  background-color: #e3f2fd;
  padding: 15px;
  border-radius: 4px;
  margin-bottom: 20px;
}

.selected-record-info h4 {
  margin-top: 0;
  margin-bottom: 10px;
  color: #1976d2;
}

.selected-record-info p {
  margin: 5px 0;
  font-size: 14px;
  color: #333;
}

.player-section {
  margin-top: 20px;
}

.player-section h4 {
  margin-bottom: 10px;
  color: #333;
}

.video-container {
  background-color: #000;
  border-radius: 4px;
  overflow: hidden;
  margin-bottom: 15px;
}

.video-player {
  width: 100%;
  min-height: 500px;
  max-height: 600px;
  display: block;
  background-color: #000;
}

.player-info {
  padding: 10px;
  background-color: #f5f5f5;
  border-radius: 4px;
  margin-top: 10px;
  display: flex;
  align-items: center;
}

.info-text {
  color: #2196f3;
  font-size: 14px;
  font-weight: 500;
}

.play-urls-info {
  margin-top: 20px;
  padding: 15px;
  background-color: #f5f5f5;
  border-radius: 4px;
}

.play-urls-info h4 {
  margin-top: 0;
  margin-bottom: 15px;
  color: #333;
}

.url-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.url-item {
  display: flex;
  align-items: center;
  padding: 10px;
  background-color: white;
  border-radius: 4px;
  border: 1px solid #e0e0e0;
}

.url-item strong {
  min-width: 80px;
  color: #2196f3;
  font-size: 14px;
}

.url-item code {
  flex: 1;
  background-color: #f5f5f5;
  padding: 5px 10px;
  border-radius: 3px;
  font-family: 'Courier New', monospace;
  font-size: 12px;
  color: #333;
  word-break: break-all;
}

.info-box {
  margin-top: 20px;
  padding: 15px;
  background-color: #e3f2fd;
  border-radius: 4px;
  border-left: 4px solid #2196f3;
}

.info-box h4 {
  margin-top: 0;
  margin-bottom: 10px;
  color: #1976d2;
}

.info-box p {
  margin: 8px 0;
  font-size: 14px;
  color: #333;
}
</style>
