<template>
	<view class="zhuapai-drop-container" id="Drop" ref="DropRef" :style="style" @touchmove="touchmove($event)"
		@touchstart="touchstart($event)">
		<view class="phone-camera-box-zhuapai">
			<camera class="camera" device-position="front" flash="off" style="width: 200px;height: 200px" :class="myClass" @initdone="onVideoSuccess" @error="handleError" @stop="handleStop"></camera>
			<!-- 用于抓拍切出去传递固定img-->
			<img :src="imgUrl" alt="" v-show="false">
		</view>
		<view v-show="showVideo" @click="noShowVideoBtn" class="shiti-video-hidden-btn">
			<icon :style="{ backgroundImage: 'url(' + iconsArr.videoCloseIcon + ')' }"></icon>
		</view>
		<view v-show="!showVideo" @click="showVideoBtn" class="shiti-video-show-btn">
			<icon :style="{ backgroundImage: 'url(' + iconsArr.videoPlayIcon + ')' }"></icon>
		</view>
    <canvas
        canvas-id="frameCanvas"
        id="frameCanvas"
        style="position: absolute;top:9999px;left: 0px;width: 100vw; height: 100vh;z-index:-2"
    ></canvas>
	</view>
</template>

<script setup>
	import {ref,onUnmounted,nextTick,computed,onMounted,reactive,getCurrentInstance} from "vue";
	import cacheManager from '@/utils/cacheManager.js';
	import * as ksApi from "@/api/kaoshi.js"
	import {
		getStaticUrl
	} from "@/utils/common.js"
	
	import {useZhuapaiStore} from "@/store/zhuapai.js"
	import {getFileUpload} from "@/api/kaoshi.js"
	
	const zhuapaiStore = useZhuapaiStore();

	const imgUrl = '';

	const cameraContext = ref(null);

  // 响应式数据
  const frameListener = ref(null)
  const isCapturing = ref(false)
  const capturedImage = ref('')
  const currentFrame = ref(null) // 存储当前帧数据
  const myInstanceR = getCurrentInstance()

	const DropRef = ref(null);
	const DropContainerRef = ref(null);
	const zhuapai = ref(0); // 单位分
	const operId = ref(null); // 单位分
	const disX = ref(0); // 移动x
	const disY = ref(0); // 移动y
	const showVideo = ref(true);
	const isBuffer = ref(false);

	const stopTimer = ref(null);
	const style = ref({
		top: "17vh",
		right: "0",
	});

	const iconsArr = reactive({
			noKaoshiImg: '',
			videoCloseIcon: '',
			videoPlayIcon: '',
	})
	const myClass = computed(() => {
		return {
			'show-video': showVideo.value,
			'hidden-video': !showVideo.value
		}
	})

	const emits = defineEmits(['init', 'success', 'error', 'cancel', 'progress'])

	function noShowVideoBtn() {
		showVideo.value = false
	}

	function showVideoBtn() {
		showVideo.value = true;
	}

	function touchmove(event) {
		// 2，获取手指移动的实时位置  需要减去位置差
		let moveX = event.touches[0].pageX - disX.value;
		let moveY = event.touches[0].pageY - disY.value;

		const systemInfo = uni.getAppBaseInfo();
		const windowHeight = systemInfo.windowHeight; // 可视区域高度 ‌:ml-citation{ref="1,3" data="citationList"}  
		const windowWidth = systemInfo.windowWidth; // 可视区域高度 ‌:ml-citation{ref="1,3" data="citationList"}  


		// 3，获取容器的宽高和拖动元素的宽高  每一次移动都会获取一次 ，建议放在外面进行获取
		// let dragHeight = DropRef.value.$el.offsetHeight;
		// let dragWidth = DropRef.value.$el.offsetWidth;
		let dragHeight = 0;
		let dragWidth = 0;

		// 4，控制范围：在元素 被拖拽的过程中 判断 元素的定位值 是否到达边界 如果到了 就不能在走了
		if (moveX <= 0) {
			moveX = 0;
		}
		// 上边界
		if (moveY <= 0) {
			moveY = 0;
		}
		//下边界  容器高度 - 拖动元素高度
		if (moveY >= windowHeight - dragHeight - 150) {
			moveY = windowHeight - dragHeight - 150;
		}
		//右边界   容器宽度 - 拖动元素宽度
		if (moveX >= windowWidth - dragWidth) {
			moveX = 0;
		}

		// 5，开始移动
		style.value.top = moveY + "px";

	}

	function touchstart(event) {
		// disX.value = event.touches[0].pageX - DropRef.value.$el.offsetLeft;
		// disY.value = event.touches[0].pageY - DropRef.value.$el.offsetTop;
		disX.value = 0;
		disY.value = 0;
	}


	function init(options) {
		zhuapai.value = options.zhuapai;
		operId.value = options.operId;
		if (zhuapai.value > 0) {
			// 启动摄像头
			nextTick(() => {
				startCamera()
				// 设定计时器
        console.log('抓拍设定', zhuapai.value)
				setInterval(() => {
          handleZhua()
        }, zhuapai.value * 60 * 1000)
			})

		}
	}
	

	function startCamera() {
		// 请求摄像头权限并获取流
		cameraContext.value = uni.createCameraContext();
    startFrameListener()
  }

	function urlToBase64(url) {
		return new Promise((resolve, reject) => {
			// #ifdef MP-WEIXIN
			// 微信小程序平台
			uni.getFileSystemManager().readFile({
				filePath: url, // 图片临时路径
				encoding: 'base64', // 指定编码格式
				success: (res) => {
					// 拼接Data URL前缀，注意图片类型可能需要根据实际情况调整（如png）
					let base64 = 'data:image/jpeg;base64,' + res.data;
					resolve(base64);
				},
				fail: (err) => {
					reject(err);
				}
			});
			// #endif
		});
	}

	function getSnapShotImage(data) {
    console.log('转转图片成base64')
		urlToBase64(data).then((d1) => {
			const imgData = d1.split(';base64,');
			
			if (!imgData.length) {
				console.error('【源 ：拍照数据异常，未找到图片二进制数据分割节点： `;base64,`】');
				return;
			}
			const opt = {
				data: imgData[1],
				prefix: 'kaoshi/zhuapai',
				suffix: 'png',
				
			};
      console.log('上传图片')
			getFileUpload(opt).then(res => {
				const dOption = {
					operId:operId.value,
					url: res.data
				}
				ksApi.getClientZhuaPaiUpdate(dOption)
					.then(res => {
						console.log('【源 ： 获取抓拍数据】');
            // 抓拍成功 继续监听
            frameListener.value.start()
					})
					.catch(err => {
						console.error('源 ：抓拍接口异常', err);
						uni.showToast({
							icon: 'none',
							title: '抓拍图片异常!'
						})
						uni.redirectTo({
							url: "/pages/client/Kaoshi/list"
						})
					});
			}).catch(err => {
				uni.showToast({
					icon: 'none',
					title: '当前网络可能存在异常，请稍后重试，如持续异常，请联系管理员。注：若异常未联系管理员，可能会影响考试结果。'
				})
				uni.redirectTo({
					url: "/pages/client/Kaoshi/list"
				})
			})
		})
		
	}
	
	function doZhuaiPai(ImageFile) {
		try {
			if (zhuapaiStore.status == 0) {
				getSnapShotImage(ImageFile);
			} else {
				const ImageFile1 = imgUrl.value;
				getSnapShotImage(ImageFile1);
			}
		} catch (err) {
			console.error('源 ：绘图失败', err);
		}
	}

	function handleZhua() {
    console.log('抓拍')
    captureSilently();
	}

	function onVideoSuccess() {
		setTimeout(() => {
			// 首次运行进行抓拍一次
			handleZhua();
		}, 3000);
	}

	function onVideoError() {
		emits('error')
	}

  function handleError() {
    emits('error')
  }

  function handleStop() {
    emits('error')
  }

	// 针对视频通话的监听处理

	function onTimeupdate() {
		if (isBuffer.value) {
			console.log('buffer')
			return;
		}
		if (!stopTimer.value) {
			return;
		}
		console.log('onTimeupdate')
		clearTimeout(stopTimer.value);
		stopTimer.value = null;
	}

	function onProgress() {
		if (stopTimer.value) {
			return;
		}
		isBuffer.value = true;
		console.log('onProgress')
		// buffer时间增大到3秒 过滤掉后续的onTimeupdate
		setTimeout(() => {isBuffer.value = false}, 3000)
		// 视频中途暂停被占用
		stopTimer.value = setTimeout(() => {
			emits('progress', false);
			console.log('结束')
		}, 10 * 1000)
	}

  /******************************************************/
  // 开始监听相机帧数据
  function startFrameListener(){
    if (!cameraContext.value) {
      uni.showToast({ title: '相机未初始化', icon: 'none' })
      return
    }

    frameListener.value = cameraContext.value.onCameraFrame((frame) => {
      // 存储当前帧数据，用于后续抓拍
      currentFrame.value = frame
      // console.log('接收帧数据:', frame.width, frame.height)
    })

    frameListener.value.start()
    isCapturing.value = true
    // uni.showToast({ title: '开始监控帧数据', icon: 'success' })
  }

  // 停止监听帧数据
  function stopFrameListener(){
    if (frameListener.value) {
      frameListener.value.stop()
      frameListener.value = null
    }
    isCapturing.value = false
    // uni.showToast({ title: '已停止监控', icon: 'success' })
  }
  // 静音抓拍核心函数
  async function captureSilently (){

    if (!isCapturing.value || !currentFrame.value) {
      uni.showToast({ title: '请先开始监控帧数据', icon: 'none' })
      return
    }
    try {
      console.log('停止前')
      // 临时停止监听以避免数据冲突
      stopFrameListener()
      console.log('开始绘制',)
      // 将帧数据绘制到Canvas并导出为图片
      await drawFrameToCanvas(currentFrame.value).then(url => {
        console.log('获取地址')
        getSnapShotImage(url)
      })
      // 重新开始监听
      startFrameListener()
    } catch (error) {
      console.log('errrrr',error)
      handleError();
    }
  }

  // 将帧数据绘制到Canvas
  function drawFrameToCanvas(frame) {
    return new Promise((resolve, reject) => {
      try {
        // 确保有有效的帧数据
        if (!frame || !frame.data || !frame.width || !frame.height) {
          reject(new Error('无效的帧数据'))
          return
        }
        // 将ArrayBuffer转换为Uint8ClampedArray[4](@ref)
        const dataArray = new Uint8Array(frame.data)
        const clampedArray = new Uint8ClampedArray(dataArray)
        console.log('clampedArray', clampedArray.length)
        // 使用wx.canvasPutImageData将帧数据绘制到Canvas[4](@ref)
        wx.canvasPutImageData({
          canvasId: 'frameCanvas',
          data: clampedArray,
          x: 0,
          y: 0,
          width: frame.width,
          height: frame.height,
          success: () => {
            // 绘制成功后，将Canvas内容转换为临时图片文件
            wx.canvasToTempFilePath({
              canvasId: 'frameCanvas',
              destWidth: frame.width,
              destHeight: frame.height,
              fileType: 'png',
              quality: 0.7,
              success: (res) => {
                capturedImage.value = res.tempFilePath
                resolve(res.tempFilePath)
              },
              fail: (err) => {
                console.log('5555',err)
                reject(new Error(`生成图片失败: ${err.errMsg}`))
              }
            }, myInstanceR.proxy)
          },
          fail: (err) => {
            console.log('6666',err)
            reject(new Error(`绘制到Canvas失败: ${err.errMsg}`))
          }
        }, myInstanceR.proxy)

      } catch (err) {

        console.log('ccccc',err)
      }
    })
  }

  /******************************************************/

  onMounted(() => {
		iconsArr.videoCloseIcon = cacheManager.get('projectImg').video_close_icon;
		iconsArr.videoPlayIcon = cacheManager.get('projectImg').video_play_icon;
	});

  onUnmounted(() => {
    stopFrameListener()
  })

	defineExpose({
		init,
		showVideoBtn
	})
</script>

<style lang="scss">
	.zhuapai-drop-container {
		width: 180rpx;
		height: 400rpx;
		margin: 0;
		padding: 0;
		z-index: 10;
		position: absolute;
		overflow: hidden;

		.phone-camera-box-zhuapai {
			width: 100%;
			height: 240rpx;
			position: absolute;
			overflow: hidden;

			.uni-video-container {
				background-color: transparent;
				pointer-events: none;
			}

			.canvas-view-box,
			.hidden-video {
				transform: translateY(10000rpx);
			}
		}

		.video-view-box {
			width: 100%;
			height: 240rpx;
			position: absolute;
		}

		.shiti-video-hidden-btn,
		.shiti-video-show-btn {
			position: absolute;
			top: 0;

			icon{
				width: 32rpx;
				height: 32rpx;
				display: block;
				background-size: cover;
				background-repeat: no-repeat;
				background-position: center;
			}
		}

		.shiti-video-hidden-btn {
			width: 60rpx;
			height: 60rpx;
			left: 0;

			icon {
				margin: 6rpx auto 6rpx 6rpx;
			}
		}

		.shiti-video-show-btn {
			background-color: #dcfbf1;
			padding: 20rpx;
			border-radius: 8rpx;
			right: 0;
		}
	}
</style>