<script setup lang="ts">
import { ref, onUnmounted } from 'vue'
import Hls from 'hls.js'
import flvjs from 'flv.js'

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

// getPushList 接口参数
const pushPage = ref(1)
const pushCount = ref(10)
const pushQuery = ref('')
const pushPushing = ref(true)
const pushMediaServerId = ref('')
const pushLoading = ref(false)
const pushError = ref('')
const pushResult = ref('')

const getPushList = async () => {
  pushLoading.value = true
  pushError.value = ''
  pushResult.value = ''

  try {
    const params = new URLSearchParams({
      page: pushPage.value.toString(),
      count: pushCount.value.toString()
    })

    // 添加可选参数
    if (pushQuery.value) {
      params.append('query', pushQuery.value)
    }
    if (pushPushing.value !== null && pushPushing.value !== undefined) {
      params.append('pushing', pushPushing.value.toString())
    }
    if (pushMediaServerId.value) {
      params.append('mediaServerId', pushMediaServerId.value)
    }

    const response = await fetch(`${GATEWAY_URL}/wvp/api/push/list?${params}`)

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

    const data = await response.json()
    pushResult.value = JSON.stringify(data, null, 2)
  } catch (error) {
    pushError.value = error instanceof Error ? error.message : '获取推流列表失败'
  } finally {
    pushLoading.value = false
  }
}

// getPushStart 接口参数
const startPushId = ref(4)
const startLoading = ref(false)
const startError = ref('')
const startResult = ref('')

const getPushStart = async () => {
  startLoading.value = true
  startError.value = ''
  startResult.value = ''

  try {
    const params = new URLSearchParams({
      id: startPushId.value.toString()
    })

    const response = await fetch(`${GATEWAY_URL}/wvp/api/push/start?${params}`)

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

    const data = await response.json()
    startResult.value = JSON.stringify(data, null, 2)
  } catch (error) {
    startError.value = error instanceof Error ? error.message : '获取播放地址失败'
  } finally {
    startLoading.value = false
  }
}

// 播放测试 - FLV和HLS
const flvUrl = ref('http://localhost:8080/zlm/live/prod.live.flv?originTypeStr=rtmp_push&audioCodec=AAC&videoCodec=H264')
const hlsUrl = ref('http://localhost:8080/zlm/live/prod/hls.m3u8?originTypeStr=rtmp_push&audioCodec=AAC&videoCodec=H264')
const testFlvError = ref('')
const testHlsError = ref('')

// FLV 播放器
let flvPlayer: any = null
const flvVideoRef = ref<HTMLVideoElement | null>(null)
const isFlvPlaying = ref(false)

const playFlv = () => {
  testFlvError.value = ''

  if (!flvVideoRef.value) {
    testFlvError.value = '视频元素未找到'
    return
  }

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

  if (flvjs.isSupported()) {
    try {
      flvPlayer = flvjs.createPlayer({
        type: 'flv',
        url: flvUrl.value,
        isLive: true,
        hasAudio: true,
        hasVideo: true,
        withCredentials: true
      })

      flvPlayer.attachMediaElement(flvVideoRef.value)
      flvPlayer.load()
      flvPlayer.play()
      isFlvPlaying.value = true

      flvPlayer.on(flvjs.Events.ERROR, (errorType: string, errorDetail: string) => {
        testFlvError.value = `播放错误: ${errorType} - ${errorDetail}`
        isFlvPlaying.value = false
      })
    } catch (error) {
      testFlvError.value = error instanceof Error ? error.message : '播放FLV失败'
      isFlvPlaying.value = false
    }
  } else {
    testFlvError.value = '当前浏览器不支持 FLV 播放'
  }
}

const stopFlv = () => {
  if (flvPlayer) {
    flvPlayer.pause()
    flvPlayer.unload()
    flvPlayer.detachMediaElement()
    flvPlayer.destroy()
    flvPlayer = null
    isFlvPlaying.value = false
  }
}

// HLS 播放器
let hlsPlayer: Hls | null = null
const hlsVideoRef = ref<HTMLVideoElement | null>(null)
const isHlsPlaying = ref(false)
let hlsRetryCount = 0
const hlsMaxRetries = 5
let hlsRetryTimer: any = null

const playHls = () => {
  testHlsError.value = ''
  hlsRetryCount = 0

  if (!hlsVideoRef.value) {
    testHlsError.value = '视频元素未找到'
    return
  }

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

  if (hlsRetryTimer) {
    clearTimeout(hlsRetryTimer)
    hlsRetryTimer = null
  }

  if (Hls.isSupported()) {
    try {
      hlsPlayer = new Hls({
        debug: false,
        enableWorker: true,
        lowLatencyMode: true,
        backBufferLength: 90,
        xhrSetup: (xhr) => {
          xhr.withCredentials = true
        },
        manifestLoadingTimeOut: 10000,
        manifestLoadingMaxRetry: 3,
        manifestLoadingRetryDelay: 1000,
        levelLoadingTimeOut: 10000,
        levelLoadingMaxRetry: 4,
        fragLoadingTimeOut: 20000,
        fragLoadingMaxRetry: 6
      })

      hlsPlayer.loadSource(hlsUrl.value)
      hlsPlayer.attachMedia(hlsVideoRef.value)

      hlsPlayer.on(Hls.Events.MANIFEST_PARSED, () => {
        console.log('HLS manifest 解析成功')
        hlsVideoRef.value?.play()
        isHlsPlaying.value = true
        testHlsError.value = ''
      })

      hlsPlayer.on(Hls.Events.ERROR, (event, data) => {
        console.error('HLS 错误:', data)

        if (data.fatal) {
          switch (data.type) {
            case Hls.ErrorTypes.NETWORK_ERROR:
              if (data.details === 'manifestLoadError' && hlsRetryCount < hlsMaxRetries) {
                // M3U8 文件加载失败,可能是还没生成,等待后重试
                hlsRetryCount++
                testHlsError.value = `M3U8 文件加载失败,正在重试 (${hlsRetryCount}/${hlsMaxRetries})...`
                console.log(`HLS 重试 ${hlsRetryCount}/${hlsMaxRetries}`)

                hlsRetryTimer = setTimeout(() => {
                  if (hlsPlayer) {
                    hlsPlayer.destroy()
                  }
                  playHls()
                }, 2000) // 等待 2 秒后重试
              } else {
                testHlsError.value = `网络错误: ${data.details}`
                isHlsPlaying.value = false
              }
              break
            case Hls.ErrorTypes.MEDIA_ERROR:
              testHlsError.value = `媒体错误: ${data.details}`
              // 尝试恢复
              if (hlsPlayer) {
                hlsPlayer.recoverMediaError()
              }
              break
            default:
              testHlsError.value = `播放错误: ${data.type} - ${data.details}`
              isHlsPlaying.value = false
              break
          }
        }
      })
    } catch (error) {
      testHlsError.value = error instanceof Error ? error.message : '播放HLS失败'
      isHlsPlaying.value = false
    }
  } else if (hlsVideoRef.value.canPlayType('application/vnd.apple.mpegurl')) {
    // Safari 原生支持 HLS
    hlsVideoRef.value.src = hlsUrl.value
    hlsVideoRef.value.play()
    isHlsPlaying.value = true
  } else {
    testHlsError.value = '当前浏览器不支持 HLS 播放'
  }
}

const stopHls = () => {
  if (hlsRetryTimer) {
    clearTimeout(hlsRetryTimer)
    hlsRetryTimer = null
  }
  if (hlsPlayer) {
    hlsPlayer.destroy()
    hlsPlayer = null
  }
  if (hlsVideoRef.value) {
    hlsVideoRef.value.pause()
    hlsVideoRef.value.src = ''
  }
  hlsRetryCount = 0
  isHlsPlaying.value = false
}

// WebRTC 播放器
let webrtcPlayer: any = null
const webrtcVideoRef = ref<HTMLVideoElement | null>(null)
const isWebrtcPlaying = ref(false)
const webrtcUrl = ref('http://localhost:8080/zlm/index/api/webrtc?app=live&stream=prod&type=play&originTypeStr=rtmp_push&audioCodec=AAC&videoCodec=H264')
const testWebrtcError = ref('')

const playWebrtc = () => {
  testWebrtcError.value = ''

  if (!webrtcVideoRef.value) {
    testWebrtcError.value = '视频元素未找到'
    return
  }

  if (webrtcPlayer) {
    webrtcPlayer.close()
    webrtcPlayer = null
  }

  try {
    // @ts-ignore
    webrtcPlayer = new window.ZLMRTCClient.Endpoint({
      element: webrtcVideoRef.value,
      debug: true,
      zlmsdpUrl: webrtcUrl.value,
      simulecast: false,
      useCamera: false,
      audioEnable: true,
      videoEnable: true,
      recvOnly: true,
      usedatachannel: false
    })

    // @ts-ignore
    webrtcPlayer.on(window.ZLMRTCClient.Events.WEBRTC_ICE_CANDIDATE_ERROR, () => {
      testWebrtcError.value = 'ICE 协商出错'
      isWebrtcPlaying.value = false
    })

    // @ts-ignore
    webrtcPlayer.on(window.ZLMRTCClient.Events.WEBRTC_ON_REMOTE_STREAMS, (e: any) => {
      console.log('WebRTC 播放成功', e.streams)
      isWebrtcPlaying.value = true
    })

    // @ts-ignore
    webrtcPlayer.on(window.ZLMRTCClient.Events.WEBRTC_OFFER_ANWSER_EXCHANGE_FAILED, (e: any) => {
      testWebrtcError.value = `offer anwser 交换失败: ${e.msg || ''}`
      isWebrtcPlaying.value = false
    })
  } catch (error) {
    testWebrtcError.value = error instanceof Error ? error.message : '播放WebRTC失败'
    isWebrtcPlaying.value = false
  }
}

const stopWebrtc = () => {
  if (webrtcPlayer) {
    webrtcPlayer.close()
    webrtcPlayer = null
  }
  isWebrtcPlaying.value = false
}

// Jessibuca 播放器
let jessibucaPlayer: any = null
const jessibucaContainerRef = ref<HTMLDivElement | null>(null)
const isJessibucaPlaying = ref(false)
const jessibucaUrl = ref('http://localhost:8080/zlm/live/prod.live.flv?originTypeStr=rtmp_push&audioCodec=AAC&videoCodec=H264')
const testJessibucaError = ref('')
const jessibucaKBps = ref(0)

const playJessibuca = () => {
  testJessibucaError.value = ''

  if (!jessibucaContainerRef.value) {
    testJessibucaError.value = '容器元素未找到'
    return
  }

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

  try {
    // @ts-ignore
    jessibucaPlayer = new window.Jessibuca({
      container: jessibucaContainerRef.value,
      videoBuffer: 0,
      isResize: false,
      useMSE: true,
      useWCS: false,
      text: '',
      controlAutoHide: false,
      debug: true,
      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', () => {
      isJessibucaPlaying.value = true
    })

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

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

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

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

    jessibucaPlayer.play(jessibucaUrl.value)
  } catch (error) {
    testJessibucaError.value = error instanceof Error ? error.message : '播放Jessibuca失败'
    isJessibucaPlaying.value = false
  }
}

const stopJessibuca = () => {
  if (jessibucaPlayer) {
    jessibucaPlayer.pause()
    jessibucaPlayer.destroy()
    jessibucaPlayer = null
  }
  isJessibucaPlaying.value = false
}

// H265Web 播放器
let h265webPlayer: any = null
const isH265webPlaying = ref(false)
const h265webUrl = ref('http://localhost:8080/zlm/live/prod.live.flv?originTypeStr=rtmp_push&audioCodec=AAC&videoCodec=H264')
const testH265webError = ref('')
const h265webLoading = ref(false)
const h265webPlayerId = 'h265webPlayerContainer'

const playH265web = () => {
  testH265webError.value = ''
  h265webLoading.value = true

  const container = document.getElementById(h265webPlayerId)
  if (!container) {
    testH265webError.value = '容器元素未找到'
    h265webLoading.value = false
    return
  }

  if (h265webPlayer) {
    h265webPlayer.release()
    h265webPlayer = null
  }

  try {
    const width = container.clientWidth || 640
    const height = container.clientHeight || 360

    // @ts-ignore
    h265webPlayer = new window.new265webjs(h265webUrl.value, {
      player: h265webPlayerId,  // 传递 ID 字符串,不是 DOM 元素
      width: width,
      height: height,
      token: 'base64:QXV0aG9yOmNoYW5neWFubG9uZ3xudW1iZXJ3b2xmLEdpdGh1YjpodHRwczovL2dpdGh1Yi5jb20vbnVtYmVyd29sZixFbWFpbDpwb3JzY2hlZ3QyM0Bmb3htYWlsLmNvbSxRUTo1MzEzNjU4NzIsSG9tZVBhZ2U6aHR0cDovL3h2aWRlby52aWRlbyxEaXNjb3JkOm51bWJlcndvbGYjODY5NCx3ZWNoYXI6bnVtYmVyd29sZjExLEJlaWppbmcsV29ya0luOkJhaWR1',
      extInfo: {
        coreProbePart: 0.4,
        probeSize: 8192,
        ignoreAudio: 0
      }
    })

    h265webPlayer.onReadyShowDone = () => {
      const result = h265webPlayer.play()
      isH265webPlaying.value = result
      h265webLoading.value = false
    }

    h265webPlayer.onLoadFinish = () => {
      console.log('H265Web 加载完成')
    }

    h265webPlayer.do()
  } catch (error) {
    testH265webError.value = error instanceof Error ? error.message : '播放H265Web失败'
    isH265webPlaying.value = false
    h265webLoading.value = false
  }
}

const stopH265web = () => {
  if (h265webPlayer) {
    h265webPlayer.release()
    h265webPlayer = null
  }
  isH265webPlaying.value = false
  h265webLoading.value = false
}

// 组件卸载时清理播放器
onUnmounted(() => {
  stopFlv()
  stopHls()
  stopWebrtc()
  stopJessibuca()
  stopH265web()
})</script>

<template>
  <div class="wvp-container">
    <h2>WVP 视频平台管理</h2>

    <div class="api-section">
      <h3>1. 获取推流列表 (getPushList)</h3>
      <div class="api-description">
        <p>通过网关调用: <code>GET /wvp/api/push/list</code></p>
        <p>实际转发到: <code>http://114.67.89.4:9090/api/push/list</code></p>
        <p>网关会自动注入 access-token 请求头</p>
      </div>

      <div class="form-row">
        <div class="form-group">
          <label>当前页 (page):</label>
          <input
            v-model.number="pushPage"
            type="number"
            min="1"
            placeholder="1"
          />
        </div>

        <div class="form-group">
          <label>每页数量 (count):</label>
          <input
            v-model.number="pushCount"
            type="number"
            min="1"
            placeholder="10"
          />
        </div>
      </div>

      <div class="form-row">
        <div class="form-group">
          <label>查询内容 (query) - 可选:</label>
          <input
            v-model="pushQuery"
            type="text"
            placeholder="留空表示不过滤"
          />
        </div>

        <div class="form-group">
          <label>流媒体ID (mediaServerId) - 可选:</label>
          <input
            v-model="pushMediaServerId"
            type="text"
            placeholder="留空表示不过滤"
          />
        </div>
      </div>

      <div class="form-group">
        <label>
          <input
            v-model="pushPushing"
            type="checkbox"
          />
          仅显示正在推流的 (pushing)
        </label>
      </div>

      <div class="button-group">
        <button @click="getPushList" :disabled="pushLoading">
          {{ pushLoading ? '查询中...' : '获取推流列表' }}
        </button>
      </div>

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

      <div v-if="pushResult" class="result-preview">
        <h4>响应结果:</h4>
        <pre>{{ pushResult }}</pre>
      </div>
    </div>

    <div class="api-section">
      <h3>2. 获取播放地址 (getPushStart)</h3>
      <div class="api-description">
        <p>通过网关调用: <code>GET /wvp/api/push/start</code></p>
        <p>实际转发到: <code>http://114.67.89.4:9090/api/push/start</code></p>
        <p>网关会自动注入 access-token 请求头</p>
        <p>返回包括 WebRTC、FLV、HLS、RTMP、RTSP 等多种播放地址</p>
      </div>

      <div class="form-group">
        <label>推流ID (id) - 必填:</label>
        <input
          v-model.number="startPushId"
          type="number"
          min="1"
          placeholder="从推流列表中获取的ID"
        />
        <small style="color: #666; display: block; margin-top: 5px;">
          提示：从上面的推流列表接口返回的数据中获取 id 字段
        </small>
      </div>

      <div class="button-group">
        <button @click="getPushStart" :disabled="startLoading">
          {{ startLoading ? '获取中...' : '获取播放地址' }}
        </button>
      </div>

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

      <div v-if="startResult" class="result-preview">
        <h4>响应结果:</h4>
        <pre>{{ startResult }}</pre>

        <div class="play-urls-info">
          <h4>播放地址说明:</h4>
          <table class="urls-table">
            <thead>
              <tr>
                <th>字段</th>
                <th>协议</th>
                <th>说明</th>
              </tr>
            </thead>
            <tbody>
              <tr>
                <td><code>rtc</code></td>
                <td>WebRTC (HTTP)</td>
                <td>低延迟播放，推荐</td>
              </tr>
              <tr>
                <td><code>rtcs</code></td>
                <td>WebRTC (HTTPS)</td>
                <td>低延迟播放（HTTPS）</td>
              </tr>
              <tr>
                <td><code>flv</code></td>
                <td>HTTP-FLV</td>
                <td>HTTP 流式播放</td>
              </tr>
              <tr>
                <td><code>ws_flv</code></td>
                <td>WebSocket-FLV</td>
                <td>WebSocket 流式播放</td>
              </tr>
              <tr>
                <td><code>hls</code></td>
                <td>HLS</td>
                <td>M3U8 播放</td>
              </tr>
              <tr>
                <td><code>rtmp</code></td>
                <td>RTMP</td>
                <td>RTMP 播放</td>
              </tr>
              <tr>
                <td><code>rtsp</code></td>
                <td>RTSP</td>
                <td>RTSP 播放</td>
              </tr>
            </tbody>
          </table>
        </div>
      </div>
    </div>

    <div class="api-section">
      <h3>3. 播放地址测试 (FLV & HLS)</h3>
      <div class="api-description">
        <p>测试通过网关访问ZLM流媒体服务器的播放地址</p>
        <p>这些地址可以直接在播放器中使用</p>
      </div>

      <div class="test-section">
        <h4>HTTP-FLV 播放器</h4>
        <div class="form-group">
          <label>FLV 播放地址:</label>
          <input
            v-model="flvUrl"
            type="text"
            placeholder="http://localhost:8080/zlm/live/prod.live.flv"
          />
        </div>

        <div class="button-group">
          <button @click="playFlv" :disabled="isFlvPlaying">
            {{ isFlvPlaying ? '播放中...' : '开始播放' }}
          </button>
          <button @click="stopFlv" :disabled="!isFlvPlaying" class="stop-button">
            停止播放
          </button>
          <a :href="flvUrl" target="_blank" class="link-button secondary">
            在新窗口打开
          </a>
        </div>

        <div class="video-container">
          <video
            ref="flvVideoRef"
            controls
            muted
            class="video-player"
          ></video>
        </div>

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

      <div class="test-section">
        <h4>HLS (M3U8) 播放器</h4>
        <div class="form-group">
          <label>HLS 播放地址:</label>
          <input
            v-model="hlsUrl"
            type="text"
            placeholder="http://localhost:8080/zlm/live/prod/hls.m3u8"
          />
        </div>

        <div class="button-group">
          <button @click="playHls" :disabled="isHlsPlaying">
            {{ isHlsPlaying ? '播放中...' : '开始播放' }}
          </button>
          <button @click="stopHls" :disabled="!isHlsPlaying" class="stop-button">
            停止播放
          </button>
          <a :href="hlsUrl" target="_blank" class="link-button secondary">
            在新窗口打开
          </a>
        </div>

        <div class="video-container">
          <video
            ref="hlsVideoRef"
            controls
            muted
            class="video-player"
          ></video>
        </div>

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

      <div class="test-section">
        <h4>WebRTC 播放器 (低延迟)</h4>
        <div class="form-group">
          <label>WebRTC 播放地址:</label>
          <input
            v-model="webrtcUrl"
            type="text"
            placeholder="http://localhost:8080/zlm/index/api/webrtc?app=live&stream=prod&type=play"
          />
        </div>

        <div class="button-group">
          <button @click="playWebrtc" :disabled="isWebrtcPlaying">
            {{ isWebrtcPlaying ? '播放中...' : '开始播放' }}
          </button>
          <button @click="stopWebrtc" :disabled="!isWebrtcPlaying" class="stop-button">
            停止播放
          </button>
        </div>

        <div class="video-container">
          <video
            ref="webrtcVideoRef"
            controls
            autoplay
            muted
            class="video-player"
          ></video>
        </div>

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

      <div class="test-section">
        <h4>Jessibuca 播放器 (多功能)</h4>
        <div class="form-group">
          <label>Jessibuca 播放地址:</label>
          <input
            v-model="jessibucaUrl"
            type="text"
            placeholder="http://localhost:8080/zlm/live/prod.live.flv"
          />
        </div>

        <div class="button-group">
          <button @click="playJessibuca" :disabled="isJessibucaPlaying">
            {{ isJessibucaPlaying ? '播放中...' : '开始播放' }}
          </button>
          <button @click="stopJessibuca" :disabled="!isJessibucaPlaying" class="stop-button">
            停止播放
          </button>
          <span v-if="isJessibucaPlaying" class="info-text">码率: {{ jessibucaKBps }} kb/s</span>
        </div>

        <div class="video-container">
          <div
            ref="jessibucaContainerRef"
            class="video-player"
            style="position: relative; min-height: 360px; height: 500px;"
          ></div>
        </div>

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

      <div class="test-section">
        <h4>H265Web 播放器 (H.265 编码)</h4>
        <div class="form-group">
          <label>H265Web 播放地址:</label>
          <input
            v-model="h265webUrl"
            type="text"
            placeholder="http://localhost:8080/zlm/live/prod.live.flv"
          />
        </div>

        <div class="button-group">
          <button @click="playH265web" :disabled="isH265webPlaying || h265webLoading">
            {{ h265webLoading ? '加载中...' : (isH265webPlaying ? '播放中...' : '开始播放') }}
          </button>
          <button @click="stopH265web" :disabled="!isH265webPlaying && !h265webLoading" class="stop-button">
            停止播放
          </button>
        </div>

        <div class="video-container">
          <div
            id="h265webPlayerContainer"
            class="video-player"
            style="position: relative; min-height: 360px;"
          >
            <div v-if="h265webLoading" class="play-loading">
              <i class="el-icon-loading" />
              视频加载中
            </div>
          </div>
        </div>

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

      <div class="info-box">
        <h4>播放器说明:</h4>
        <p><strong>FLV (flv.js):</strong> 使用 flv.js 库播放 FLV 流，兼容性好</p>
        <p><strong>HLS (hls.js):</strong> 使用 hls.js 库播放 M3U8 流，适合点播</p>
        <p><strong>WebRTC:</strong> 超低延迟 (< 500ms)，适合实时监控，需要 HTTPS 或 localhost</p>
        <p><strong>Jessibuca:</strong> 功能强大的多格式播放器，支持 FLV/HLS/WebSocket-FLV，有心跳重连</p>
        <p><strong>H265Web:</strong> 支持 H.265/HEVC 编码，高清低码率，需要 token 授权</p>
        <p><strong>注意:</strong> 确保推流正在进行，否则播放地址会返回404错误</p>
      </div>
    </div>
  </div>
</template>

<style scoped>
.wvp-container {
  max-width: 1000px;
  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[type="checkbox"] {
  margin-right: 8px;
}

.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;
}

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

.result-preview {
  margin-top: 20px;
  padding: 15px;
  background-color: #f5f5f5;
  border-radius: 4px;
}

.result-preview h4 {
  margin-top: 0;
  margin-bottom: 10px;
  color: #333;
}

.result-preview pre {
  background-color: #2d2d2d;
  color: #f8f8f2;
  padding: 15px;
  border-radius: 4px;
  overflow-x: auto;
  font-family: 'Courier New', monospace;
  font-size: 13px;
  line-height: 1.5;
  margin: 0;
}

.play-urls-info {
  margin-top: 20px;
  padding-top: 20px;
  border-top: 1px solid #ddd;
}

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

.urls-table {
  width: 100%;
  border-collapse: collapse;
  background-color: white;
  border-radius: 4px;
  overflow: hidden;
}

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

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

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

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

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

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

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

.test-section {
  margin-top: 20px;
  padding: 15px;
  background-color: #fafafa;
  border-radius: 4px;
  border: 1px solid #e0e0e0;
}

.test-section h4 {
  margin-top: 0;
  margin-bottom: 15px;
  color: #2196f3;
  font-size: 16px;
}

.success {
  margin-top: 15px;
  padding: 12px;
  background-color: #e8f5e9;
  color: #2e7d32;
  border-radius: 4px;
  font-size: 14px;
  white-space: pre-wrap;
}

.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;
}

.link-button {
  display: inline-block;
  padding: 10px 20px;
  background-color: #2196f3;
  color: white;
  text-decoration: none;
  border-radius: 4px;
  font-size: 14px;
  font-weight: 500;
  transition: background-color 0.3s ease;
  text-align: center;
}

.link-button:hover {
  background-color: #1976d2;
}

.link-button.secondary {
  background-color: #4caf50;
}

.link-button.secondary:hover {
  background-color: #45a049;
}

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

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

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

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

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

.play-loading {
  width: 100%;
  height: 100%;
  min-height: 360px;
  color: rgb(255, 255, 255);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 18px;
  background-color: #000;
}

.play-loading i {
  margin-right: 10px;
  font-size: 24px;
}
</style>
