<template>
  <div class="stream-player">
    <div class="controls">
      <input
        v-model="streamId"
        placeholder="输入流ID"
        class="stream-id-input"
      />
      <input
        v-model="authToken"
        placeholder="输入认证Token"
        class="auth-token-input"
      />
      <button @click="startPlay" class="start-btn">开始播放</button>
      <button @click="stopPlay" class="stop-btn" :disabled="!isPlaying">停止播放</button>
    </div>

    <div class="status" v-if="statusMessage" :class="statusClass">{{ statusMessage }}</div>

    <!-- 显式显示当前加载的TS文件名称 -->
    <div class="ts-info" v-if="currentTsFile || loadedTsFiles.length">
      <div class="current-ts">当前加载: <strong>{{ currentTsFile || '无' }}</strong></div>
      <div class="loaded-ts-list">
        已加载列表:
        <span
          v-for="(ts, index) in loadedTsFiles"
          :key="index"
          :class="{ 'current': ts === currentTsFile }"
        >
          {{ ts }}
        </span>
      </div>
    </div>

    <div class="video-container">
      <video
        id="streamVideo"
        class="video-js vjs-big-play-centered"
        controls
        autoplay
        playsinline
      ></video>
    </div>
  </div>
</template>

<script>
import videojs from 'video.js';
import 'video.js/dist/video-js.css';
import '@videojs/http-streaming';

export default {
  name: 'StreamPlayer',
  data() {
    return {
      streamId: '',
      authToken: '',
      player: null,
      isPlaying: false,
      statusMessage: '',
      requestCounter: 0,
      manifestRefreshTimer: null,
      lastSegmentIndex: -1,
      currentTsFile: '', // 当前正在加载的TS文件
      loadedTsFiles: [] // 已加载的TS文件列表
    };
  },
  computed: {
    statusClass() {
      if (!this.statusMessage) return '';
      if (this.statusMessage.includes('错误')) return 'status-error';
      if (this.statusMessage.includes('播放中')) return 'status-playing';
      return 'status-info';
    }
  },
  methods: {
    // 提取TS文件名（从URL中）
    extractTsFileName(url) {
      // 匹配URL中的xxx.ts格式文件名
      const match = url.match(/([^\/]+\.ts)(\?|$)/);
      return match ? match[1] : null;
    },

    startPlay() {
      // 输入验证
      if (!this.streamId.trim()) {
        this.statusMessage = '错误: 请输入流ID';
        return;
      }

      this.requestCounter++;
      const timestamp = new Date().getTime();
      const cacheBuster = `${timestamp}-${this.requestCounter}-${Math.random().toString(36).substr(2, 8)}`;
      const hlsUrl = `/api/hls/${this.streamId}/stream.m3u8?cache-buster=${cacheBuster}`;

      this.statusMessage = '正在连接流...';
      this.currentTsFile = '';
      this.loadedTsFiles = []; // 重置已加载列表

      // 销毁现有播放器
      if (this.player) {
        this.stopPlay();
      }
      // 初始化播放器
      this.player = videojs('streamVideo', {
        autoplay: true,
        controls: true,
        responsive: true,
        fluid: true,
        preload: 'none',
        sources: [{
          src: hlsUrl,
          type: 'application/x-mpegURL'
        }],
        html5: {
          vhs: {
            overrideNative: true,
            enableLowInitialLatency: true,
            cacheDuration: 0,
            maxBufferLength: 8,
            maxMaxBufferLength: 15
          },
          hls: {
            xhrSetup: (xhr, url) => {
              // 添加认证Token
              if (this.authToken) {
                xhr.setRequestHeader('Authorization', `Bearer ${this.authToken}`);
              }
              // 缓存控制
              xhr.setRequestHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
              xhr.setRequestHeader('Pragma', 'no-cache');
              xhr.setRequestHeader('Expires', '0');

              // 检测TS文件请求并记录文件名
              if (url.includes('.ts')) {
                const tsFileName = this.extractTsFileName(url);
                if (tsFileName) {
                  // 更新当前加载的TS文件
                  this.currentTsFile = tsFileName;
                  // 添加到已加载列表（去重）
                  if (!this.loadedTsFiles.includes(tsFileName)) {
                    this.loadedTsFiles.push(tsFileName);
                    // 只保留最近10个记录，避免列表过长
                    if (this.loadedTsFiles.length > 10) {
                      this.loadedTsFiles.shift();
                    }
                    console.log(`[TS加载] ${tsFileName}`);
                  }
                }
              }
            },
            lowLatencyMode: true,
            onError: (error) => {
              console.error('HLS错误:', error);
              if (this.player && this.player.hls) {
                this.player.hls.startLoad();
              }
            }
          }
        }
      });
      // 监听播放器事件
      this.player.on('loadedmetadata', () => {
        this.isPlaying = true;
        this.statusMessage = '播放中...';
        this.startManifestRefresh();
      });

      this.player.on('error', () => {
        const error = this.player.error();
        const errorMsg = this.getErrorMessage(error);
        this.statusMessage = `播放错误: ${errorMsg}`;
        this.isPlaying = false;
        console.error('播放器错误详情:', error);

        // 解码或加载错误时尝试重连
        if (error.code === 3 || error.code === 4) {
          setTimeout(() => {
            if (!this.isPlaying) {
              this.statusMessage = '尝试重新连接...';
              this.startPlay();
            }
          }, 3000);
        }
      });

      this.player.on('ended', () => {
        this.statusMessage = '播放结束';
        this.isPlaying = false;
        this.clearManifestRefresh();
      });

      // 监听片段加载完成事件
      this.player.on('hlsSegmentLoaded', (event, data) => {
        const tsFileName = this.extractTsFileName(data.segment.uri);
        if (tsFileName) {
          console.log(`[TS加载完成] ${tsFileName}`);
        }
      });
    },

    stopPlay() {
      if (this.player) {
        this.player.pause();
        this.player.dispose();
        this.player = null;
      }
      this.isPlaying = false;
      this.statusMessage = '已停止播放';
      this.clearManifestRefresh();
      this.currentTsFile = '';
    },

    // 启动M3U8定期刷新
    startManifestRefresh() {
      this.clearManifestRefresh();
      this.manifestRefreshTimer = setInterval(() => {
        if (this.player && this.player.hls) {
          try {
            const playlist = this.player.hls.playlists.selectedVideoPlaylist;
            if (playlist && playlist.segments) {
              const currentSegments = playlist.segments.length;
              // 检测是否有新片段
              if (currentSegments > this.lastSegmentIndex + 1) {
                this.lastSegmentIndex = currentSegments - 1;
                const newTsFile = this.extractTsFileName(playlist.segments[this.lastSegmentIndex].uri);
                console.log(`[检测到新片段] ${newTsFile || '未知片段'}`);
                this.player.hls.startLoad();
              }
            }
          } catch (e) {
            console.error('刷新播放列表时出错:', e);
          }
        }
      }, 3000);
    },

    // 清除刷新定时器
    clearManifestRefresh() {
      if (this.manifestRefreshTimer) {
        clearInterval(this.manifestRefreshTimer);
        this.manifestRefreshTimer = null;
      }
    },

    getErrorMessage(error) {
      switch (error.code) {
        case 1: return '加载视频时发生错误';
        case 2: return '视频格式不支持（请确认使用H.264/AAC编码）';
        case 3: return '视频无法解码（可能是文件损坏或编码问题）';
        case 4: return '媒体源无法加载（检查网络或服务器）';
        case 5: return '未授权访问（Token无效或已过期）';
        default: return `未知错误 (${error.code}): ${error.message || ''}`;
      }
    }
  },
  beforeDestroy() {
    this.clearManifestRefresh();
    if (this.player) {
      this.player.dispose();
    }
  }
};
</script>

<style scoped>
.stream-player {
  max-width: 1280px;
  margin: 0 auto;
  padding: 20px;
  font-family: Arial, sans-serif;
}

.controls {
  display: flex;
  gap: 10px;
  margin-bottom: 20px;
  flex-wrap: wrap;
  align-items: center;
}

.stream-id-input, .auth-token-input {
  flex: 1;
  min-width: 200px;
  padding: 8px 12px;
  border: 1px solid #ddd;
  border-radius: 4px;
  font-size: 14px;
}

.start-btn, .stop-btn {
  padding: 8px 16px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 14px;
  transition: opacity 0.2s;
}

.start-btn {
  background-color: #4CAF50;
  color: white;
}

.start-btn:hover {
  background-color: #45a049;
}

.stop-btn {
  background-color: #f44336;
  color: white;
  opacity: 0.7;
}

.stop-btn:not(:disabled) {
  opacity: 1;
}

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

.stop-btn:disabled {
  cursor: not-allowed;
}

.status {
  margin-bottom: 15px;
  padding: 10px 15px;
  border-radius: 4px;
  background-color: #f5f5f5;
  font-size: 14px;
}

.status-error {
  background-color: #ffebee;
  color: #b71c1c;
  border: 1px solid #ef9a9a;
}

.status-playing {
  background-color: #e8f5e9;
  color: #2e7d32;
  border: 1px solid #a5d6a7;
}

.status-info {
  background-color: #e3f2fd;
  color: #0d47a1;
  border: 1px solid #bbdefb;
}

/* TS文件信息样式 */
.ts-info {
  margin: 15px 0;
  padding: 10px 15px;
  background-color: #f9f9f9;
  border-radius: 4px;
  font-size: 14px;
}

.current-ts {
  margin-bottom: 8px;
  color: #333;
}

.loaded-ts-list {
  color: #666;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 5px;
}

.loaded-ts-list span {
  padding: 3px 8px;
  background-color: #e0e0e0;
  border-radius: 3px;
  font-size: 12px;
}

.loaded-ts-list span.current {
  background-color: #4CAF50;
  color: white;
}

.video-container {
  width: 100%;
  background-color: #000;
  border-radius: 4px;
  overflow: hidden;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
}

:deep(.video-js) {
  width: 100%;
  height: auto;
  min-height: 400px;
}

/* 响应式调整 */
@media (max-width: 768px) {
  .controls {
    flex-direction: column;
  }

  .stream-id-input, .auth-token-input {
    width: 100%;
    min-width: unset;
  }

  .start-btn, .stop-btn {
    width: 100%;
  }

  :deep(.video-js) {
    min-height: 250px;
  }
}
</style>
