<template>
  <div class="page">
    <div class="page-content">
      <div class="layout-container">
        <!-- 左侧表单区域 -->
        <box-ground-glass style="height: 100%; overflow: hidden">
          <el-scrollbar height="100%">
            <div class="left-panel">
              <div class="device-section">
                <div class="device-header">
                  <div class="device-title-box">
                    <el-icon class="icon"><icon-mdi-web-camera></icon-mdi-web-camera></el-icon>
                    <span class="title">摄像头预览</span>
                  </div>
                  <div class="camera-status">
                    <span class="status-dot" :class="{ active: localTrackState }"></span>
                    <span class="status-text">{{ localTrackState ? '设备正常' : '未初始化' }}</span>
                  </div>
                </div>
                <!-- 预览容器 -->
                <div ref="localPlayerContainer" class="camera-preview-container"></div>
              </div>
              <!-- 麦克风音量指示器 -->
              <div class="device-section">
                <div class="device-header">
                  <div class="device-title-box">
                    <icon-mdi-microphone class="audio-icon"></icon-mdi-microphone>
                    <span class="title">麦克风音量</span>
                  </div>
                </div>
                <div class="audio-level-bar-box">
                  <div class="audio-level-bar">
                    <div class="level-indicator" :style="{ width: audioLevel + '%' }"></div>
                  </div>
                  <div class="audio-level-text">{{ audioLevel }}%</div>
                </div>
              </div>
              <!-- 扬声器 -->
              <div class="device-section">
                <div class="device-header">
                  <div class="device-title-box">
                    <icon-mdi-microphone class="icon"></icon-mdi-microphone>
                    <span class="title">扬声器检测</span>
                  </div>
                </div>
                <div style="display: flex; gap: 20px; align-items: flex-start; justify-content: center">
                  <div style="color: #666666">点击右侧按钮时会播放一声"滴"的声音,请注意聆听是否听到?</div>
                  <button class="btn btn-secondary" style="width: 240px" @click="testSpeaker">
                    <icon-mdi-volume-source class="btn-icon"></icon-mdi-volume-source>
                    <span>测试扬声器</span>
                  </button>
                </div>
              </div>
            </div>
          </el-scrollbar>
        </box-ground-glass>
        <!-- 右侧预览区域 -->
        <box-ground-glass style="height: 100%; overflow: hidden">
          <el-scrollbar height="100%">
            <div class="right-panel">
              <el-form ref="formRef" labelWidth="90px" hideRequiredAsterisk :model="formData" :rules="formRules" size="large">
                <el-form-item label="课程信息" prop="courseRoomName">
                  <template #label>
                    <div class="title-box">
                      <span class="title">课程信息</span>
                    </div>
                  </template>
                  <el-input :modelValue="`${courseRoomName} (${courseTeacher || '未分配'})`" disabled></el-input>
                </el-form-item>
                <el-form-item label="预计时间" prop="courseRoomName">
                  <template #label>
                    <div class="title-box">
                      <span class="title">预计时间</span>
                    </div>
                  </template>
                  <el-input :modelValue="`${dateInfo.showStartTime} 至 ${dateInfo.showEndTime}`" disabled></el-input>
                </el-form-item>
                <el-form-item label="用户信息" prop="courseRoomName">
                  <template #label>
                    <div class="title-box">
                      <span class="title">用户信息</span>
                    </div>
                  </template>
                  <el-input :modelValue="`${userName} (${role === 'student' ? '学生' : '教师'})`" disabled></el-input>
                </el-form-item>
                <el-form-item label="摄像头" prop="selectedCamera">
                  <template #label>
                    <div class="title-box">
                      <span class="title">摄像头</span>
                    </div>
                  </template>
                  <el-select v-model="formData.selectedCamera" placeholder="选择摄像头" @change="handleCameraChange">
                    <el-option v-for="camera in cameraList" :key="camera.deviceId" :label="camera.label" :value="camera.deviceId"></el-option>
                  </el-select>
                </el-form-item>
                <el-form-item label="麦克风" prop="selectedMicrophone">
                  <template #label>
                    <div class="title-box">
                      <span class="title">麦克风</span>
                    </div>
                  </template>
                  <el-select v-model="formData.selectedMicrophone" placeholder="选择麦克风" @change="handleMicrophoneChange">
                    <el-option v-for="mic in microphoneList" :key="mic.deviceId" :label="mic.label" :value="mic.deviceId"></el-option>
                  </el-select>
                </el-form-item>
              </el-form>
            </div>
          </el-scrollbar>
        </box-ground-glass>
      </div>
      <div class="footer-bottom-box">
        <el-space alignment="center" :size="25">
          <div></div>
        </el-space>
        <el-space alignment="center" :size="25">
          <app-button-full-screen></app-button-full-screen>
          <app-button-back-page></app-button-back-page>
          <button v-if="role === 'teacher'" class="btn btn-monitoring" @click="handleJoinRoom('monitor')">
            <icon-mdi-login class="btn-icon"></icon-mdi-login>
            <span>进入监控</span>
          </button>
          <button class="btn btn-primary" @click="handleJoinRoom('classroom')">
            <icon-mdi-login class="btn-icon"></icon-mdi-login>
            <span>进入课程</span>
          </button>
        </el-space>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
  import IconMdiLogin from '~icons/mdi/login';
  import IconMdiMicrophone from '~icons/mdi/microphone';
  import IconMdiVolumeSource from '~icons/mdi/volume-source';
  import IconMdiWebCamera from '~icons/mdi/web-camera';
  import AgoraRTC, { type ICameraVideoTrack, type IMicrophoneAudioTrack } from 'agora-rtc-sdk-ng';
  import { computed, onMounted, onUnmounted, ref } from 'vue';
  import { useRouter } from 'vue-router';
  import { useStorage } from '@vueuse/core';
  import type { FormInstance, FormRules } from 'element-plus';
  import { getDateObj } from '@/utils/time';
  /** 设置日志级别 */
  AgoraRTC.setLogLevel(2);
  const router = useRouter();
  const meetingStore = useMeetingStore();
  const userStore = useUserStore();
  /** 用户角色 */
  const role = ref<'student' | 'teacher'>(Number(userStore.userInfo?.roleType) === 0 ? 'student' : 'teacher');

  /** 表单引用 */
  const formRef = ref<FormInstance>();
  /** 时间信息 */
  const dateInfo = computed(() => {
    const startTimeInfo = getDateObj(meetingStore.currCourseRoom?.startTime || Date.now());
    const endTimeInfo = getDateObj(meetingStore.currCourseRoom?.endTime || Date.now());
    return {
      showStartTime: `${startTimeInfo.month}-${startTimeInfo.day} ${startTimeInfo.hour}:${startTimeInfo.minute}`,
      showEndTime: `${endTimeInfo.month}-${endTimeInfo.day} ${endTimeInfo.hour}:${endTimeInfo.minute}`,
      endTimestamp: endTimeInfo.timestamp,
    };
  });
  /** 表单数据 */
  const formData = ref({
    selectedCamera: useStorage<string>('meeting_selected_camera', ''),
    selectedMicrophone: useStorage<string>('meeting_selected_microphone', ''),
    // eslint-disable-next-line vue/no-ref-object-reactivity-loss
    endTimestamp: dateInfo.value.endTimestamp,
  });

  /** 表单验证规则 */
  const formRules: FormRules = {
    selectedCamera: [{ required: true, message: '请选择摄像头', trigger: 'change' }],
    selectedMicrophone: [{ required: true, message: '请选择麦克风', trigger: 'change' }],
    meetingDuration: [
      { required: true, message: '请输入预计时长', trigger: 'blur' },
      { type: 'number', min: 5, max: 240, message: '时长必须在 5-240 分钟之间', trigger: 'blur' },
    ],
  };
  /** 课程房间名称 */
  const courseRoomName = computed(() => meetingStore.currCourseRoom?.name || '');
  /** 作业id */
  const homeworkId = computed(() => meetingStore.currCourseRoom?.id || 0);
  /** 课程房间教师 */
  const courseTeacher = computed(() => meetingStore.currCourseRoom?.teacher || '');

  /** 用户名称 */
  const userName = computed(() => userStore.userInfo?.name || '');

  /** 摄像头设备列表 */
  const cameraList = ref<Array<{ deviceId: string; label: string }>>([]);
  /** 麦克风设备列表 */
  const microphoneList = ref<Array<{ deviceId: string; label: string }>>([]);

  /** 本地轨道状态（是否已初始化） */
  const localTrackState = ref<boolean>(false);
  /** 麦克风音量百分比（0-100） */
  const audioLevel = ref<number>(0);
  /** 本地视频轨道实例 */
  let localVideoTrack: ICameraVideoTrack | null = null;
  /** 本地音频轨道实例 */
  let localAudioTrack: IMicrophoneAudioTrack | null = null;
  /** 本地视频播放容器元素 */
  const localPlayerContainer = ref<HTMLDivElement | null>(null);
  /** 初始化锁，防止重复初始化导致的竞态条件 */
  const isInitializing = ref(false);

  /** 音频音量监测定时器 */
  let audioLevelTimer: number | null = null;

  onMounted(async () => {
    // 页面加载时就初始化本地轨道，让用户能看到预览
    try {
      formData.value.endTimestamp = dateInfo.value.endTimestamp;
      await getDevices();
      await initLocalTracks();
    } catch (error: any) {
      console.error('页面加载时初始化轨道失败:', error);
      Toast.error(error.message || '初始化设备失败，请检查设备权限');
    }
  });

  onUnmounted(() => {
    cleanup();
  });

  /**
   * 获取可用的摄像头和麦克风设备列表
   * @returns {Promise<void>}
   * @throws {Error} 当获取设备失败时抛出错误
   */
  async function getDevices(): Promise<void> {
    try {
      const cameras = await AgoraRTC.getCameras();
      const microphones = await AgoraRTC.getMicrophones();
      cameraList.value = cameras || [];
      microphoneList.value = microphones || [];

      // 处理摄像头默认选择逻辑
      if (cameraList.value.length > 0) {
        // 检查当前存储的设备是否存在于列表中
        const currentCameraExists = cameraList.value.some((camera) => camera.deviceId === formData.value.selectedCamera);
        // 如果不存在或当前未选择，则默认选择第一个
        if (!formData.value.selectedCamera || !currentCameraExists) {
          formData.value.selectedCamera = cameraList.value[0].deviceId;
        }
      } else {
        formData.value.selectedCamera = '';
      }

      // 处理麦克风默认选择逻辑
      if (microphoneList.value.length > 0) {
        // 检查当前存储的设备是否存在于列表中
        const currentMicExists = microphoneList.value.some((mic) => mic.deviceId === formData.value.selectedMicrophone);
        // 如果不存在或当前未选择，则默认选择第一个
        if (!formData.value.selectedMicrophone || !currentMicExists) {
          formData.value.selectedMicrophone = microphoneList.value[0].deviceId;
        }
      } else {
        formData.value.selectedMicrophone = '';
      }

      return Promise.resolve();
    } catch (error: any) {
      console.error('获取设备列表失败:', error);
      return Promise.reject(new Error('无法获取摄像头和麦克风，请检查设备权限', { cause: error }));
    }
  }

  /**
   * 初始化本地轨道（摄像头和麦克风）
   * @returns {Promise<boolean>} 是否初始化成功
   * @throws {Error} 当设备初始化失败时抛出错误
   */
  async function initLocalTracks(): Promise<boolean> {
    if (isInitializing.value) {
      return false;
    }
    isInitializing.value = true;

    try {
      // 在创建新轨道之前，确保先关闭旧的轨道
      if (localVideoTrack) {
        localVideoTrack.close();
        localVideoTrack.stop();
        localVideoTrack = null;
      }
      if (localAudioTrack) {
        localAudioTrack.close();
        localAudioTrack.stop();
        localAudioTrack = null;
      }

      // 初始化本地视频轨道
      try {
        // eslint-disable-next-line require-atomic-updates
        localVideoTrack = await AgoraRTC.createCameraVideoTrack({
          cameraId: formData.value.selectedCamera || undefined,
          encoderConfig: { width: 640, height: 480, frameRate: 15, bitrateMin: 300, bitrateMax: 600 },
        });
      } catch (error: any) {
        console.error('摄像头初始化失败:', error);
        const errorMessage =
          error.code === 'DEVICE_NOT_FOUND' || error.message?.includes('Requested device not found')
            ? '未找到摄像头设备，请检查设备连接'
            : error.code === 'NOT_READABLE' || error.name === 'NotReadableError' || error.message?.includes('Device in use')
              ? '摄像头被占用，请关闭其他使用摄像头的程序'
              : '摄像头初始化失败，请检查设备权限';
        isInitializing.value = false;
        return Promise.reject(new Error(errorMessage, { cause: error }));
      }

      // 初始化本地音频轨道
      try {
        // eslint-disable-next-line require-atomic-updates
        localAudioTrack = await AgoraRTC.createMicrophoneAudioTrack({
          microphoneId: formData.value.selectedMicrophone || undefined,
          encoderConfig: { sampleRate: 16000, bitrate: 16 },
        });
      } catch (error: any) {
        console.error('麦克风初始化失败:', error);
        const errorMessage =
          error.code === 'DEVICE_NOT_FOUND' || error.message?.includes('Requested device not found')
            ? '未找到麦克风设备，请检查设备连接'
            : error.code === 'NOT_READABLE' || error.name === 'NotReadableError' || error.message?.includes('Device in use')
              ? '麦克风被占用，请关闭其他使用麦克风的程序'
              : '麦克风初始化失败，请检查设备权限';
        isInitializing.value = false;
        return Promise.reject(new Error(errorMessage, { cause: error }));
      }

      // 播放视频预览
      if (localPlayerContainer.value && localVideoTrack) {
        localVideoTrack.play(localPlayerContainer.value);
      }

      localTrackState.value = true;
      console.log('本地轨道初始化成功');

      // 开始监听音频音量
      startAudioLevelMonitoring();

      isInitializing.value = false;
      return true;
    } catch (error: any) {
      // 捕获其他未预期的错误
      console.error('初始化本地轨道失败:', error);
      isInitializing.value = false;
      return Promise.reject(new Error('初始化设备失败，请检查设备权限', { cause: error }));
    }
  }

  /**
   * 处理摄像头切换事件
   * @param {string} deviceId - 要切换的摄像头设备 ID
   */
  async function handleCameraChange(deviceId: string) {
    try {
      if (localVideoTrack) {
        await localVideoTrack.setDevice(deviceId);
      }
    } catch (error) {
      console.error('切换摄像头失败:', error);
      Toast.error('切换摄像头失败');
    }
  }

  /**
   * 处理麦克风切换事件
   * @param {string} deviceId - 要切换的麦克风设备 ID
   */
  async function handleMicrophoneChange(deviceId: string) {
    try {
      if (localAudioTrack) {
        await localAudioTrack.setDevice(deviceId);
      }
    } catch (error) {
      console.error('切换麦克风失败:', error);
      Toast.error('切换麦克风失败');
    }
  }

  /**
   * 测试扬声器：播放提示音
   */
  function testSpeaker() {
    try {
      // 创建临时的 AudioContext 来播放提示音
      const audioContext = new (window.AudioContext || (window as any).webkitAudioContext)();
      const oscillator = audioContext.createOscillator();
      const gainNode = audioContext.createGain();
      oscillator.connect(gainNode);
      gainNode.connect(audioContext.destination);
      // 设置频率和音量
      oscillator.frequency.value = 440; // A4 音符
      oscillator.type = 'sine';
      gainNode.gain.value = 0.3;

      // 播放 0.5 秒
      oscillator.start();
      setTimeout(() => {
        oscillator.stop();
        audioContext.close();
      }, 500);

      Toast.success('提示音已播放');
    } catch (error) {
      console.error('测试扬声器失败:', error);
      Toast.error('测试扬声器失败');
    }
  }

  /**
   * 处理学生加入房间操作
   */
  async function handleJoinRoom(target: 'classroom' | 'monitor' = 'classroom') {
    try {
      await formRef.value?.validate();
    } catch (err: any) {
      Toast.error('请完善信息');
      return;
    }
    // 触发表单验证

    console.log('即将跳转到 meeting-room 页面');
    const endTimestamp = Number(formData.value.endTimestamp);
    const now = Date.now();
    if (!Number.isFinite(endTimestamp) || endTimestamp < now + 5 * 60 * 1000) {
      Toast.error('结束时间不能小于当前时间的5分钟');
      return;
    }
    const joinMode = role.value === 'student' ? 'student' : target === 'monitor' ? 'monitor' : 'classroom';
    const targetPath =
      role.value === 'student' ? '/meeting/meeting-room-student' : target === 'monitor' ? '/meeting/meeting-room-monitor' : '/meeting/meeting-room';
    router.push({
      path: targetPath,
      query: {
        homeworkId: homeworkId.value,
        name: courseRoomName.value,
        role: role.value,
        cameraDeviceId: formData.value.selectedCamera,
        microphoneDeviceId: formData.value.selectedMicrophone,
        endTimestamp,
        joinMode,
      },
    });
  }

  /**
   * 清理资源：关闭音视频轨道
   */
  function cleanup() {
    try {
      // 停止音量监测
      stopAudioLevelMonitoring();

      if (localAudioTrack) {
        localAudioTrack.close();
        localAudioTrack.stop();
        localAudioTrack = null;
      }
      if (localVideoTrack) {
        localVideoTrack.close();
        localVideoTrack.stop();
        localVideoTrack = null;
      }
      localTrackState.value = false;
      audioLevel.value = 0;
    } catch (error) {
      console.error('清理资源失败:', error);
    }
  }

  /**
   * 开始监听音频音量
   * 每 100ms 更新一次音量指示器
   */
  function startAudioLevelMonitoring() {
    if (audioLevelTimer) {
      return;
    }

    audioLevelTimer = window.setInterval(() => {
      if (localAudioTrack) {
        // 获取实时音量数据 (0-1)
        const volume = localAudioTrack.getVolumeLevel?.() || 0;
        // 转换为百分比 (0-100)
        audioLevel.value = Math.min(100, Math.round(volume * 100));
      } else {
        audioLevel.value = 0;
      }
    }, 100); // 每 100ms 更新一次
  }

  /**
   * 停止监听音频音量
   * 清理定时器，释放资源
   */
  function stopAudioLevelMonitoring() {
    if (audioLevelTimer) {
      clearInterval(audioLevelTimer);
      audioLevelTimer = null;
    }
  }
</script>

<style lang="scss" scoped>
  .page {
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100vh;
    padding: 15px;
    overflow: hidden;

    .page-content {
      position: relative;
      box-sizing: border-box;
      display: flex;
      flex-direction: column;
      align-items: flex-start;
      justify-content: flex-start;
      width: 100%;
      height: 100%;
      overflow: hidden;
      background: rgba(255, 255, 255, 0.4);
      border: 1px solid rgba(255, 255, 255, 0.2);
      border-radius: 20px;
      box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.1);
    }
  }

  .layout-container {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 24px;
    width: 100%;
    height: 100%;
    padding: 20px;
    overflow: hidden;

    // 右侧预览面板
    .left-panel {
      display: flex;
      flex-direction: column;
      gap: 24px;
      width: 100%;
      height: auto;
      min-height: 0;
      padding: 15px 24px;
      overflow: hidden;
      border-radius: 24px;

      .device-section {
        display: flex;
        flex-direction: column;
        width: 100%;

        .device-header {
          display: flex;
          align-items: center;
          justify-content: space-between;
          margin-bottom: 10px;

          .device-title-box {
            display: flex;
            gap: 5px;
            align-items: center;
            justify-content: center;

            .icon {
              font-size: 18px;
              color: #374151;
            }

            .title {
              font-size: 18px;
              font-weight: bold;
              color: #374151;
            }
          }

          .camera-status {
            display: flex;
            gap: 6px;
            align-items: center;

            .status-dot {
              width: 8px;
              height: 8px;
              background: #9ca3af;
              border-radius: 50%;
              transition: all 0.3s ease;

              &.active {
                background: #10b981;
                box-shadow: 0 0 0 2px rgba(16, 185, 129, 0.2);
              }
            }

            .status-text {
              font-size: 12px;
              color: #6b7280;
            }
          }
        }
      }

      .camera-preview-container {
        position: relative;
        width: 360px;
        max-width: 100%;
        aspect-ratio: 16 / 9;
        overflow: hidden;
        background: #000000;
        border-radius: 12px;

        video {
          width: 100%;
          height: 100%;
          object-fit: cover;
        }
      }

      // 音频音量指示器
      .audio-level-bar-box {
        display: flex;
        gap: 8px;
        align-items: center;
        justify-content: center;

        .audio-level-bar {
          position: relative;
          width: 100%;
          height: 24px;
          overflow: hidden;
          background: #e5e7eb;
          border-radius: 12px;

          .level-indicator {
            height: 100%;
            background: linear-gradient(90deg, #10b981 0%, #34d399 50%, #6ee7b7 100%);
            border-radius: 12px;
            box-shadow: 0 0 10px rgba(16, 185, 129, 0.5);
            transition: width 0.1s ease;
          }
        }

        .audio-level-text {
          font-size: 14px;
          font-weight: 600;
          color: #6b7280;
          text-align: right;
        }
      }
    }
    // 左侧面板
    .right-panel {
      box-sizing: border-box;
      min-height: 0;
      padding: 15px;

      .title-box {
        display: inline-flex;
        gap: 5px;
        align-items: center;
        justify-content: center;

        .icon {
          font-size: 18px;
          color: #374151;
        }

        .title {
          font-size: 18px;
          font-weight: bold;
          color: #374151;
        }
      }
    }
  }

  .btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    padding: 12px;
    font-size: 16px;
    font-weight: 600;
    cursor: pointer;
    border: none;
    border-radius: 12px;
    transition: all 0.3s ease;

    .btn-icon {
      width: 22px;
      height: 22px;
      margin-right: 5px;
    }

    &.btn-primary {
      width: 220px;
      margin-bottom: 10px;
      color: #ffffff;
      background: linear-gradient(45deg, #f07f70, #fccd6d);
      box-shadow: 0 4px 12px #fccd6d;

      &:hover:not(:disabled) {
        box-shadow: 0 6px 15px rgba(240, 127, 112, 0.5);
        transform: translateY(-2px);
      }
    }

    &.btn-monitoring {
      width: 220px;
      margin-bottom: 10px;
      color: #ffffff;
      background: linear-gradient(45deg, #bd62fd, #c7aaff);
      box-shadow: 0 4px 12px #c7aaff;

      &:hover:not(:disabled) {
        box-shadow: 0 6px 15px rgba(189, 98, 253, 0.5);
        transform: translateY(-2px);
      }
    }

    &.btn-secondary {
      color: #ffffff;
      background: linear-gradient(45deg, #667eea, #764ba2);
      box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);

      &:hover:not(:disabled) {
        box-shadow: 0 6px 15px rgba(102, 126, 234, 0.5);
        transform: translateY(-2px);
      }
    }
  }

  .footer-bottom-box {
    display: flex;
    justify-content: space-between;
    width: 100%;
    padding: 15px;
    padding-bottom: 10px;
  }

  // 强制设置 el-scrollbar 内部容器高度为 100%
  :deep(.el-scrollbar__wrap) {
    height: 100% !important;
  }

  :deep(.el-scrollbar__view) {
    height: 100% !important;
  }
</style>
