<template>
  <div class="camera-container">
    <!-- 相机模块 -->
    <el-card class="camera-module">
      <div class="header-container">
        <div class="header-title">相机1模块</div>
        <div class="header-buttons">
          <el-button type="primary" @click="getCameraList" :disabled="isInitialized">获取相机列表</el-button>
        </div>
      </div>

      <template v-if="cameraList.length > 0">
        <!-- 相机参数模块 - 紧凑版 -->
        <div class="camera-params compact">
          <div class="section-title">相机参数设置</div>
          <el-form inline class="params-form">
            <el-form-item label="分辨率">
              <el-select v-model="globalParams.resolution" style="width: 140px">
                <el-option label="2560×1440" value="2560x1440"></el-option>
                <el-option label="1920×1080" value="1920x1080"></el-option>
                <el-option label="1280×960" value="1280x960"></el-option>
              </el-select>
            </el-form-item>

            <el-form-item label="帧率">
              <el-select v-model="globalParams.fps" style="width: 80px">
                <el-option label="15" :value="15"></el-option>
                <el-option label="30" :value="30"></el-option>
                <el-option label="60" :value="60"></el-option>
              </el-select>
            </el-form-item>

            <el-form-item label="保存路径">
              <el-input v-model="globalParams.savePath" placeholder="/images" style="width: 180px"></el-input>
            </el-form-item>

            <el-form-item>
              <el-button-group>
                <el-button type="primary" @click="initAllCameras" icon="el-icon-refresh" :disabled="isInitialized">
                  {{ isInitialized ? '已初始化' : '初始化' }}
                </el-button>
                <el-switch v-model="globalParams.lowFpsMode" active-text="低帧率" inactive-text="原始帧"
                  @change="toggleFpsMode" style="margin-left: 10px;" :disabled="!isInitialized" />
                <el-button type="danger" @click="closeAllCameras" icon="el-icon-close">关闭</el-button>
              </el-button-group>
              <el-tag :type="isInitialized ? 'success' : 'info'">
                {{ isInitialized ? '已初始化' : '未初始化' }}
              </el-tag>
            </el-form-item>
          </el-form>
        </div>

        <!-- 视频帧显示区 -->
        <div class="section-title">视频帧显示</div>
        <el-row :gutter="20" class="frame-display-row">
          <el-col :span="8" v-for="camera in cameraList" :key="camera.id" class="frame-display-wrapper">
            <el-card class="frame-display">
              <div slot="header" class="clearfix">
                <div class="frame-title">
                  <span class="camera-id">相机 {{ camera.id }}_{{ camera.name }}</span>
                  <span class="camera-spec">({{ camera.width }}×{{ camera.height }} @{{ camera.fps }}fps)</span>
                </div>
                <div class="frane-config">
                  <el-popover placement="right" width="400" trigger="click">
                    <div class="config-content">
                      <div class="config-item">
                        <div class="config-item-label">
                          <span class="demonstration">亮度</span>
                        </div>
                        <div class="config-item-slider">
                          <el-slider v-model="camera.brightness" :min="-100" :max="100" @change="handleBrightnessChange(camera)"></el-slider>
                        </div>
                        <div class="config-item-value">
                          {{ camera.brightness }}
                        </div>
                      </div>
                      <div class="config-item">
                        <div class="config-item-label">
                          <span class="demonstration">对比度</span>
                        </div>
                        <div class="config-item-slider">
                          <el-slider v-model="camera.contrast" :min="-100" :max="100" @change="handleContrastChange(camera)"></el-slider>
                        </div>
                        <div class="config-item-value">
                          {{ camera.contrast }}
                        </div>
                      </div>
                      <div class="config-item">
                        <div class="config-item-label">
                          <span class="demonstration">饱和度</span>
                        </div>
                        <div class="config-item-slider">
                          <el-slider v-model="camera.saturation" :min="-100" :max="100" @change="handleSaturationChange(camera)"></el-slider>
                        </div>
                        <div class="config-item-value">
                          {{ camera.saturation }}
                        </div>
                      </div>
                      <div class="config-item">
                        <div class="config-item-label">
                          <span class="demonstration">色调</span>
                        </div>
                        <div class="config-item-slider">
                          <el-slider v-model="camera.hue" :min="-100" :max="100" @change="handleHueChange(camera)"></el-slider>
                        </div>
                        <div class="config-item-value">
                          {{ camera.hue }}
                        </div>
                      </div>
                      <div class="config-item">
                        <div class="config-item-label">
                          <span class="demonstration">增益</span>
                        </div>
                        <div class="config-item-slider">
                          <el-slider v-model="camera.gain" :min="-100" :max="100" @change="handleGainChange(camera)"></el-slider>
                        </div>
                        <div class="config-item-value">
                          {{ camera.gain }}
                        </div>
                      </div>
                      <div class="config-item">
                        <div class="config-item-label">
                          <span class="demonstration">曝光</span>
                        </div>
                        <div class="config-item-slider">
                          <el-slider v-model="camera.exposure" :min="-100" :max="100" @change="handleExposureChange(camera)"></el-slider>
                        </div>
                        <div class="config-item-value">
                          {{ camera.exposure }}
                        </div>
                      </div>
                    </div>
                    <el-button slot="reference" circle icon="el-icon-more-outline" size="mini"></el-button>
                  </el-popover>
                </div>
              </div>
              <div class="frame-header">
                <el-select v-model="camera.cameraOrientation" style="width: 120px" @change="configCamera(camera)">
                  <el-option label="不指定" value="不指定"></el-option>
                  <el-option label="后侧" value="后侧"></el-option>
                  <el-option label="左侧" value="左侧"></el-option>
                  <el-option label="右侧" value="右侧"></el-option>
                </el-select>
                <el-button-group style="margin-left: 10px;">
                  <el-button type="success" @click="startStream(camera)" size="mini"
                    icon="el-icon-video-play">链接</el-button>
                  <el-button type="danger" @click="stopStream(camera)" size="mini"
                    icon="el-icon-switch-button">断链</el-button>
                </el-button-group>
              </div>
              <div v-if="!camera.imageData" ref="frameDisplay" style="width: 100%; height: 280px; background: #000;">
              </div>
              <canvas v-else :ref="'canvas_' + camera.id" style="width: 100%; height: 100%; background: #000;"></canvas>
              <div class="status-info">
                <el-tag v-if="camera.statusInfo" type="info" size="small">{{ camera.statusInfo }}</el-tag>
              </div>
              <div class="status-log">
                <el-alert v-if="camera.captureLog" :title="camera.captureLog" type="info" :closable="false" show-icon
                  style="padding: 5px 10px;" />
              </div>
            </el-card>
          </el-col>
        </el-row>

        <!-- 全局控制模块 -->
        <div class="section-title">全局控制</div>
        <div class="global-controls">
          <el-button-group>
            <el-button type="success" @click="captureImage">捕获</el-button>
          </el-button-group>
        </div>
      </template>
      <div v-else class="empty-tip">
        <el-empty description="暂无相机，请点击右上角按钮获取相机列表"></el-empty>
      </div>
    </el-card>
  </div>
</template>

<script>
import {
  baseURLConsole2
} from '@/utils/url'
import {
  getStillCameraList,
  initializeStillCamera,
  setStillCameraOrientation,
  lowStillCamera,
  getWebSocketLink,
  closeStillCamera,
  captureStillCamera,
  disconnectStillCamera,
  setCameraBrightness,
  setCameraContrast,
  setCameraSaturation,
  setCameraHue,
  setCameraGain,
  setCameraExposure
} from '@/api/stillCamera'
import Worker from '@/components/workers/stillCamera.worker.js'
export default {
  name: 'StillCamera',
  data() {
    return {
      globalParams: {
        fps: 30,//帧率
        resolution: '2560x1440',//分别率
        savePath: 'images/captures',//存储路径
        lowFpsMode: false,//低帧率模式开关
      },
      cameraList: [],//相机列表
      isInitialized: false, // 初始化状态
      workers: {} // 存储每个相机对应的worker
    }
  },
  methods: {
    //获取相机列表
    getCameraList() {
      // 调用接口获取相机列表
      getStillCameraList().then(res => {
        console.log(res)
        if (res.data.length > 0) {
          let list = [];
          res.data.forEach(item => {
            const worker = new Worker();
            worker.onmessage = (e) => this.handleWorkerMessage(item.camera_id, e.data);
            list.push({
              id: item.camera_id,
              name: item.name,
              width: 0,
              height: 0,
              fps: 0,
              cameraOrientation: '不指定',//方位
              websocket: null,
              reconnectAttempts: 0,//重连次数限制
              imageData: null,
              objectURL: null,
              statusInfo: null,
              captureLog: '等待连接',
              worker, // 存储worker引用
              brightness: 0,//亮度
              contrast: 0,//对比度
              saturation: 0,//饱和度
              hue: 0,//色相
              gain: 0,//增益
              exposure: 0,//曝光
            })
            this.workers[item.camera_id] = worker;
          })
          this.cameraList = list;
          this.$message.success(`获取到 ${this.cameraList.length} 个相机`)
          //查询相机原有的webScoket链接并关闭
          getWebSocketLink().then(res => {
            console.log(res)
            if (res.data.connected_cameras.length > 0) {
              res.data.connected_cameras.forEach(item => {
                disconnectStillCamera(item)
              })
            }
          })
        } else {
          this.$message.error('当前没有相机')
        }
      })
    },
    //初始化所有相机
    initAllCameras() {
      // 调用接口初始化所有相机
      let cameraIds = [];
      const [width, height] = this.globalParams.resolution.split('x')
      //设置相机
      this.cameraList.forEach(camera => {
        cameraIds.push(camera.id)
      })
      //设置参数
      let param = {
        camera_ids: cameraIds.join(","),
        init_params: {
          resolution_width: parseInt(width),
          resolution_height: parseInt(height),
          fps: this.globalParams.fps
        }
      }
      initializeStillCamera(param).then(res => {
        console.log(res)
        this.cameraList.forEach(camera => {
          let cameraConfig = res.data.initialized_cameras.find(item => item.camera_id == camera.id)
          if (cameraConfig) {
            camera.brightness = cameraConfig.brightness
            camera.contrast = cameraConfig.contrast
            camera.saturation = cameraConfig.saturation
            camera.hue = cameraConfig.hue
            camera.gain = cameraConfig.gain
            camera.exposure = cameraConfig.exposure
          }
          camera.width = parseInt(width)
          camera.height = parseInt(height)
          camera.fps = this.globalParams.fps
        })
        this.isInitialized = true
        this.$message.success(`初始化所有相机成功`)
      })
    },

    // 切换帧率模式
    toggleFpsMode(isLowFps) {
      // 调用接口设置帧率模式
      let cameraIds = [];
      this.cameraList.forEach(camera => {
        cameraIds.push(camera.id)
      });

      let param = {
        camera_ids: cameraIds.join(','),
        fps: isLowFps ? 5 : 25
      };

      lowStillCamera(param).then(res => {
        this.$message.success(isLowFps ? '已启用低帧率模式' : '已恢复原始帧率');
      })
    },
    //配置相机
    configCamera(camera) {
      let param = {
        camera_id: camera.id,
        orientation: camera.cameraOrientation
      }
      //调用接口配置相机
      setStillCameraOrientation(param).then(res => {
        console.log(res)
        this.$message.success(`配置相机成功`)
      })
    },
    //处理亮度变化
    handleBrightnessChange(camera) {
      let param = {
        camera_id: camera.id,
        brightness: camera.brightness
      }
      setCameraBrightness(param).then(res => {
        console.log(res)
        this.$message.success(`设置亮度成功`)
      })
    },
    //处理对比度变化
    handleContrastChange(camera) {
      let param = {
        camera_id: camera.id,
        contrast: camera.contrast
      }
      setCameraContrast(param).then(res => {
        console.log(res)
        this.$message.success(`设置对比度成功`)
      })
    },
    //处理饱和度变化
    handleSaturationChange(camera) {
      let param = {
        camera_id: camera.id,
        saturation: camera.saturation
      }
      setCameraSaturation(param).then(res => {
        console.log(res)
        this.$message.success(`设置饱和度成功`)
      })
    },
    //处理色调变化
    handleHueChange(camera) {
      let param = {
        camera_id: camera.id,
        hue: camera.hue
      }
      setCameraHue(param).then(res => {
        console.log(res)
        this.$message.success(`设置色相成功`)
      })
    },
    //处理增益变化
    handleGainChange(camera) {
      let param = {
        camera_id: camera.id,
        gain: camera.gain
      }
      setCameraGain(param).then(res => {
        console.log(res)
        this.$message.success(`设置增益成功`)
      })
    },
    //处理曝光变化
    handleExposureChange(camera) {
      let param = {
        camera_id: camera.id,
        exposure: camera.exposure
      }
      setCameraExposure(param).then(res => {
        console.log(res)
        this.$message.success(`设置曝光成功`)
      })
    },
    //开始链接webScoke
    startStream(camera) {
      camera.worker.postMessage({
        action: 'connect',
        id: camera.id,
        baseURL: baseURLConsole2
      });
    },
    // 处理worker消息
    handleWorkerMessage(cameraId, data) {
      const camera = this.cameraList.find(c => c.id === cameraId);
      if (!camera) return;

      const { type, message, blob, width, height, performance, encode_time_ms, data_size_kb } = data;

      switch (type) {
        case 'status':
          camera.captureLog = message;
          break;

        case 'error':
          camera.captureLog = message;
          break;

        case 'frame':
          // 使用 createImageBitmap 处理 Blob 数据
          createImageBitmap(blob).then(bitmap => {
            camera.imageData = bitmap;
            this.$nextTick(() => {
              this.renderImageToCanvas(camera);
            });

            // 更新状态信息
            let statusInfo = `分辨率: ${width}x${height}`;
            if (performance) {
              statusInfo += ` | 实际FPS: ${performance.actual_fps} | 目标FPS: ${performance.target_fps}`;
            }
            if (encode_time_ms) {
              statusInfo += ` | 编码耗时: ${encode_time_ms}ms`;
            }
            if (data_size_kb) {
              statusInfo += ` | 数据大小: ${data_size_kb}KB`;
            }
            camera.statusInfo = statusInfo;
          });
          break;
      }
    },
    // 渲染图像到canvas
    renderImageToCanvas(camera) {
      if (!camera.imageData) return;
      const canvas = this.$refs[`canvas_${camera.id}`];
      if (!canvas || !canvas[0]) return;

      // 计算保持比例的尺寸
      const containerWidth = canvas[0].parentElement.clientWidth;
      const ratio = camera.imageData.width / camera.imageData.height;
      const height = containerWidth / ratio;

      // 设置canvas尺寸
      canvas[0].width = containerWidth;
      canvas[0].height = height;

      // 绘制图像
      const ctx = canvas[0].getContext('2d');
      ctx.clearRect(0, 0, canvas[0].width, canvas[0].height);
      ctx.drawImage(camera.imageData, 0, 0, canvas[0].width, canvas[0].height);
    },

    //断开链接
    stopStream(camera) {
      disconnectStillCamera(camera.id).then(res => {
        this.$message.success(`断开链接成功`);
        camera.worker.postMessage({
          action: 'disconnect'
        });

        this.$nextTick(() => {
          camera.imageData = null;
          camera.statusInfo = null;
          camera.captureLog = '等待链接';
        });
      });
    },

    //关闭所有相机
    closeAllCameras() {

      let cameraIds = [];
      this.cameraList.forEach(camera => {
        cameraIds.push(camera.id);
        if (camera.websocket) {
          this.stopStream(camera)
        }
      });

      let param = {
        camera_ids: cameraIds.join(',')
      };

      closeStillCamera(param).then(res => {
        console.log(res);
        this.cameraList = [];
        Object.values(this.workers).forEach(worker => worker.terminate());
        this.workers = {};
        this.isInitialized = false
        this.globalParams = {
          fps: 30,//帧率
          resolution: '2560x1440',//分别率
          savePath: 'images/captures',//存储路径
          lowFpsMode: false,//低帧率模式开关
        },
          this.$message.success('已关闭所有相机');
      })
    },

    //捕捉帧
    captureImage(camera) {
      let cameraIds = [];
      this.cameraList.forEach(camera => {
        cameraIds.push(camera.id);
      });
      //调用接口捕获帧
      let param = {
        camera_ids: cameraIds.join(','),
        user_name: this.$store.getters.username,
        save_dir: this.globalParams.savePath,
      }
      captureStillCamera(param).then(res => {
        this.$message.success(`捕获图像成功`)
      })
    },


  },
  // 2. 组件销毁时清理
  beforeDestroy() {
    // 关闭所有相机连接
    this.cameraList.forEach(camera => {
      this.disconnectStillCamera(camera.id);
    });
    // 终止所有worker
    Object.values(this.workers).forEach(worker => worker.terminate());
    this.workers = {};
  }
}
</script>

<style scoped>
.camera-container {
  padding: 20px;
  background-color: #f5f7fa;
}

/* 相机模块样式 */
.camera-module {
  border-radius: 8px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  margin-bottom: 20px;
}

/* 模块标题样式 */
.section-title {
  font-size: 16px;
  font-weight: bold;
  color: #303133;
  margin-bottom: 15px;
  padding-bottom: 8px;
  border-bottom: 2px solid #409eff;
}

/* 相机参数模块样式 */
.camera-params {
  padding: 20px;
  margin-bottom: 20px;
  background-color: #fff;
  border-radius: 6px;
  box-shadow: 0 1px 6px rgba(0, 0, 0, 0.1);
  border: 1px solid #ebeef5;
  position: relative;
}

.camera-params::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 4px;
  height: 100%;
  background-color: #409eff;
  border-radius: 4px 0 0 4px;
}

/* 紧凑版参数模块 */
.camera-params.compact {
  padding: 15px;
}

.camera-params.compact .params-form {
  margin-top: 10px;
}

.camera-params.compact .el-form-item {
  margin-bottom: 0;
  margin-right: 15px;
}

.camera-params.compact .el-form-item__label {
  font-size: 12px;
  color: #606266;
  padding-right: 5px;
}

.camera-params.compact .el-input-number {
  line-height: 28px;
}


/* 视频帧显示区样式 */
.frame-display-row {
  margin-bottom: 20px;
}

.frame-display {
  height: 100%;
  border-radius: 8px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  margin-bottom: 15px;
  background-color: #fff;
  border: 1px solid #ebeef5;
}

/* 全局控制模块样式 */
.global-controls {
  margin-top: 20px;
  padding: 20px;
  background-color: #fff;
  border-radius: 6px;
  box-shadow: 0 1px 6px rgba(0, 0, 0, 0.1);
  border: 1px solid #ebeef5;
  text-align: center;
}

.header-container {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
}

.header-title {
  font-size: 24px;
  font-weight: bold;
  color: #303133;
  padding-left: 10px;
  border-left: 4px solid #409eff;
}

.header-buttons {
  display: flex;
  gap: 10px;
}

.patient-info {
  margin-bottom: 20px;
  border-radius: 8px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}

.info-item {
  display: flex;
  align-items: center;
  margin-bottom: 10px;
  font-size: 14px;
}

.info-item label {
  width: 80px;
  color: #666;
  font-weight: 500;
}

.camera-list {
  display: flex;
  flex-direction: column;
  gap: 15px;
}

.camera-item {
  display: flex;
  justify-content: space-between;
  padding: 15px;
  border: 1px solid #ebeef5;
  border-radius: 6px;
  background-color: #fff;
  transition: all 0.3s;
  margin-bottom: 10px;
}

.camera-item:hover {
  transform: translateY(-3px);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}

.selected-camera {
  border: 2px solid #409eff;
  background-color: #f0f7ff;
}

.clearfix {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-around;
  flex-wrap: nowrap;
}

.frame-title {
  flex: 1;
  display: flex;
  align-items: center;
  font-size: 16px;
}

.frane-config {
  text-align: right;
  flex: 1;
}

.config-content {
  width: 400px;
}

.config-item {
  display: flex;
  width: 100%;
  justify-content: column-reverse;
  align-items: center;
}

.config-item-label {
  margin: 5px;
  flex: 3;
}

.config-item-slider {
  margin: 5px;
  flex: 10;
}

.config-item-value {
  margin: 5px;
  flex: 1;
}


.camera-id {
  font-weight: bold;
  margin-right: 8px;
}

.camera-spec {
  font-size: 12px;
  color: #909399;
}

.frame-header {
  padding: 8px 15px;
  display: flex;
  justify-content: center;
  background-color: #f5f7fa;
  border-bottom: 1px solid #ebeef5;
}

.camera-info {
  flex: 1;
}

.info-row {
  display: flex;
  align-items: center;
  margin-bottom: 8px;
}

.info-row label {
  width: 70px;
  font-size: 12px;
  color: #666;
  text-align: right;
  padding-right: 8px;
  flex-shrink: 0;
}

.camera-actions {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
}

.frame-display-row {
  margin-bottom: 20px;
}

.frame-display {
  height: 100%;
  border-radius: 8px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}

.frame-display-wrapper {
  height: 100%;
}

.global-controls {
  margin-top: 20px;
  text-align: center;
  padding: 15px;
  background-color: #f5f7fa;
  border-radius: 6px;
}

.capture-controls {
  margin-top: 15px;
  padding: 15px;
  background-color: #f5f7fa;
  border-radius: 6px;
}

.button-group {
  display: flex;
  justify-content: center;
  gap: 10px;
  margin-bottom: 15px;
}
</style>
