<script lang="ts" setup>
import { nextTick, onMounted, onUpdated, reactive, ref, watch } from 'vue';
import { useMessage } from 'naive-ui';
import { Camera, Images } from '@vicons/ionicons5';
import { CleaningServicesOutlined } from '@vicons/material';
import { DrawPolygon } from '@vicons/fa';
import { api_base64ToWebURl } from '@/api/index';
import html2canvas from 'html2canvas';
import JSMpeg from '@cycjimmy/jsmpeg-player';
import { ArrowReset24Filled } from '@vicons/fluent';
import type { UploadFileInfo } from 'naive-ui';

// const serviceUrl = 'ws://192.168.1.140:9999';

const serviceUrl = import.meta.env.VITE_VIDEO_URL;
const apiUrl = import.meta.env.VITE_SERVICE_URL;
const webSocketUrl = import.meta.env.VITE_WEBSOCKET_URL;

const msg = useMessage()
const imgURL = ref('https://jzo2o-oss-11.oss-cn-hangzhou.aliyuncs.com/1ac80abd-5328-4135-b8ce-7eafbb569af5.jpg');
const nodeStr = ref("");

const props = defineProps({
  val: {
    type: String,
    require: true
  },
  image: {
    type: String,
    require: true
  },
  callback: {
    type: Function,
    require: true
  },
  imgCallback: {
    type: Function,
    require: true
  },
  address: {
    type: String,
    require: true
  }
})

//"(x,y),(x,y),(x,y),(x,y)"
const parseCoordinates = (str: string) => {
  // 定义正则表达式来匹配坐标对
  const regex = /\((\d+),(\d+)\)/g;
  let match;
  const coordinates = [];

  // 执行匹配
  while ((match = regex.exec(str)) !== null) {
    // 提取x和y的值
    const x = parseInt(match[1], 10);
    const y = parseInt(match[2], 10);

    // 构建对象并添加到数组
    coordinates.push({ "x": x, 'y': y });
  }

  return coordinates;
}

// (x,y),(x,y)
// arr => (x，y),
const autoComputePercentage = (): string => {
  // if (elNodes.value.length < 2) return ``;

  // eslint-disable-next-line no-underscore-dangle
  const _w = 1920;
  // eslint-disable-next-line no-underscore-dangle
  const _h = 1080;

  // eslint-disable-next-line no-underscore-dangle
  let _str = ``;

  const { width, height } = canvasBoxConf;

  for (const info of node) {
    _str += `(${(((info.x as number) / width) * _w).toFixed(0)},${(((info.y as number) / height) * _h).toFixed(0)}),`;
  }

  return _str.slice(0, _str.length - 1);
};



// ======================= IMG 上传 | S
const beforeUpload = (data: { file: UploadFileInfo; fileList: UploadFileInfo[] }): boolean => {

  // if (data.file.file?.type !== 'image/png') {
  //   msg.error('仅支持JPEG/JPG/PNG三种图片格式上传!');
  //   return false;
  // }

  // if (data.file.file?.type !== 'image/jpg') {
  //   msg.error('仅支持JPEG/JPG/PNG三种图片格式上传!');
  //   return false;
  // }

  // if (data.file.file?.type !== 'image/jpeg') {
  //   msg.error('仅支持JPEG/JPG/PNG三种图片格式上传!');
  //   return false;
  // }

  return true;
};

const fileList = ref<UploadFileInfo[]>([]);
const handleFinish = ({ file, event }: { file: UploadFileInfo; event?: ProgressEvent }) => {
  const res = event?.target && event?.target?.response && JSON.parse(event?.target?.response);
  if (res.code === 200) {
    props?.imgCallback(res.data);
    imgURL.value = res.data;
    // fileList = []
    msg.success('图片上传成功!');
    initCanvasImg(() => drawCanvas())
  }
  return file;
};
// ======================= IMG 上传 | E



// ======================= 截图抓取 | S
const handleCaptureVideoImg = () => {
  nextTick(() => {
    html2canvas(document.getElementById('canvas-3') as HTMLElement)
      .then(canvas => {
        // dialogSpin.value = false;
        api_base64ToWebURl(canvas.toDataURL('image/png')).then(res => {
          if (res.data.code === 200) {
            imgURL.value = res.data.data;
            props?.imgCallback(res.data.data);
            msg.success('截图抓取成功!');
            initCanvasImg(() => drawCanvas())
          }
        });
      })
      .catch(() => {
        // dialogSpin.value = false;
      });
  });
};
// ======================= 截图抓取 | E




/**
 *   绘制
 *
 *      - 坐标 加进去
 *      - 循环绘制
 *
 *   上一步
 *
 *      - 删除 ctx.clearRect(0, 0, canvas.width, canvas.height);
 *      - 循环绘制
 *
 *  清空
 *
 *      -  删除  ctx1.value.clearRect(0, 0, config.value.width, config.value.height); // 清除画布，以便重新绘制
 *      -  重新放图片
 *  平移
 *
 *      -
 *
 *
 *  自动转化 (x,y),(x,y)
 *
 *  反向转换 str => arr
 *
 *  canva 图片 绘制 层级前后顺序
 *
 *
 *
 */

// (691,140),(611,709),(1142,760),(674,79),(590,54),(691,140)
let old = [{
  x: 10,
  y: 10
},
{
  x: 400,
  y: 100
},
{
  x: 300,
  y: 200
},
{
  x: 100,
  y: 120
},
{
  x: 60,
  y: 50
},
{
  x: 10,
  y: 10
},]
let node = reactive<{ x: number, y: number }[]>([

]);

const canvasContext = ref(null);

const canvasBoxConf = reactive({
  width: 200,
  height: 200,
});

const isTranslate = ref(false)


//  点击
const handleClickCanvas = (e) => {
  if (isTranslate.value) return;
  // if (!openType.value) return message.error('点击多边形后, 开始绘制!');

  // if (!imgUrl.value) return message.error('请选择上传底图后, 开始绘制!');

  if (node.length > 2) {
    // eslint-disable-next-line no-underscore-dangle
    const _f = node[0];
    // eslint-disable-next-line no-underscore-dangle
    const _l = node[node.length - 1];
    if (_f.x === _l.x && _f.y === _l.y) return msg.warning('多边形已闭合, 不可继续绘制!');
  }

  updateNodeList(e);

  drawCanvas();


  props.callback(autoComputePercentage());

  // 计算
  console.log(autoComputePercentage());
}

// 节点
const updateNodeList = (e) => {
  /**
  *   1. 收集点位
  *
  *   2. 点击最终一个点位， 如靠近第一个点位附近， 形成完美的图形， 磁吸效果
  */

  let { offsetX, offsetY } = e;
  let _curNode = {
    x: offsetX,
    y: offsetY
  };

  const _lastNode = node[0];

  if (node.length > 2 && Math.abs(offsetX - _lastNode.x) < 15 && Math.abs(offsetY - _lastNode.y) < 15) return node.push(_lastNode);


  return node.push(_curNode)
}


// 绘制
const drawCanvas = () => {
  console.log("==================== 点位", node)
  let ctx = canvasContext.value;
  // ctx.globalCompositeOperation = 'destination-over';
  // ctx.clearRect(0, 0, canvasBoxConf.width, canvasBoxConf.height);
  // ctx.reset()
  // 线
  const drawCanvasLine = (prev, next) => {
    if (node.length < 1) return new Error("xian1 必须2个点位起！");
    ctx.beginPath();
    ctx.moveTo(prev.x, prev.y);
    ctx.lineTo(next.x, next.y);
    ctx.strokeStyle = 'red'; // 线条颜色
    ctx.lineWidth = 5; // 线条宽度
    ctx.stroke();
  }

  // 点
  const drawCanvasMarker = () => {

  }

  node.reduce((prevI, nextI) => {

    // 线
    drawCanvasLine(prevI, nextI);

    // 标记
    drawCanvasMarker(prevI, nextI);


    return nextI;
  })

}


// 数据对齐
const getHeightOrWidth = () => {
  const canvas = document.getElementById('DrawCompoent');
  const canvasWrap = document.getElementById('DrawWrap');

  canvas.height = canvasWrap.scrollHeight;
  canvas.width = canvasWrap.scrollWidth;

  return {
    _canvas_el: canvas,
    _canvas_wrap_el: canvasWrap,
    _canvas_context: canvas.getContext('2d'),
    width: canvasWrap.scrollWidth,
    height: canvasWrap.scrollHeight
  };
};


// 图片
const initCanvasImg = (afterCallback?: Function) => {
  let ctx = canvasContext.value;
  canvasContext.value.clearRect(0, 0, canvasBoxConf.width, canvasBoxConf.height);
  let img = new Image();
  img.src = imgURL.value;
  console.log("imgURL.value ============== Draw", imgURL.value)
  img.onload = () => {
    ctx.drawImage(img, 0, 0, canvasBoxConf.width, canvasBoxConf.height); // 第一个参数是图片，第二个和第三个参数是坐标，第四和第五个参数是图片宽高或裁剪区域
    afterCallback && afterCallback()
    // afterCallback || msg.warning("图片初始化需要传递一个 回调函数< Canvas 绘制函数>！")
  };
};


// 清空
const handleDrawClean = () => {
  if (node.length === 0) {
    return msg.warning("当前画布是空白的!");
  };
  canvasContext.value.clearRect(0, 0, canvasBoxConf.width, canvasBoxConf.height);
  initCanvasImg()
  return node = [];
}


// 平移
const handleTransalteCanvas = () => {
  isTranslate.value = true;
}

// 返回上一步
const handleResetDraw = () => {
  if (node.length == 0) return msg.warning("暂无可撤销内容！");
  node.pop()
  return initCanvasImg(() => {
    drawCanvas()
  })
};

// 鼠标抬起
const onMouseDown = (e) => {
  let canvas = canvasBoxConf.el;
  const rect = canvas.getBoundingClientRect();
  const x = e.clientX - rect.left;
  const y = e.clientY - rect.top;
  console.log(x, y)

  /**
   *   1. 点击多边形 - 新增
   *   2. 点击平移 - 不增
   *
   *
   */
  // handleTransalteCanvas(x, y)

  // drawCanvas()
}

// 初始化
const fempegVideoInit = () => {
  // 临时测试
  const rtsp1 = props.address;

  if (!props.address) {
    return msg.error("视频地址为空！")
  }

  // eslint-disable-next-line no-new
  return new JSMpeg.Player(
    `${serviceUrl}/rtsp?url=${btoa(rtsp1)}&scale=640:-1&-b:v=1k&brightness=0.2&saturation=1.8`,
    {
      canvas: document.getElementById('canvas-3'),
      preserveDrawingBuffer: true
    }
  );
};

onMounted(() => {
  // canvas 基本信息
  let { width, height, _canvas_context, _canvas_el, _canvas_wrap_el } = getHeightOrWidth();

  canvasContext.value = _canvas_context;
  canvasBoxConf.width = width;
  canvasBoxConf.height = height;
  canvasBoxConf.el = _canvas_el;

  console.log("======================================= address", props);

  fempegVideoInit()

  imgURL.value = props.image;
  nodeStr.value = props.val;


  if (nodeStr.value) {
    console.log("node ==============", parseCoordinates(nodeStr.value))
    node = parseCoordinates(nodeStr.value);

    node.forEach(item => {
      item.x = ((item.x / 1920) * canvasBoxConf.width).toFixed(0);
      item.y = ((item.y / 1080) * canvasBoxConf.height).toFixed(0);
    })
    // console.log("node ============", node)
  }


  // node = old;
  // drawCanvas()
  initCanvasImg(() => drawCanvas())
});






</script>

<template>
  <!-- 抓图测试-->
  <div id="canvas-4"> <canvas id="canvas-3"></canvas> </div>
  <!--  -->
  <!-- <NSpin > -->
  <div>
    <!-- 工具栏 -->
    <div class="draw-tool">
      <div>
        <div>
          <div style="text-align: center" @click="handleCaptureVideoImg">
            <NIcon size="26">
              <Camera />
            </NIcon>
            <br />
            <span style="display: inline-block">获取抓图</span>
          </div>
        </div>
        <!-- DrawPolygon -->
        <div @click="isTranslate = false">
          <div style="text-align: center">
            <NIcon size="26">
              <DrawPolygon />
            </NIcon>
            <br />
            <span style="display: inline-block">多边形</span>
          </div>
        </div>
        <!-- <div @click="isTranslate = true">
          <div style="text-align: center">
            <NIcon size="26">
              <HandMove />
            </NIcon>
            <br />
            <span style="display: inline-block">平移</span>
          </div>
        </div> -->
        <div @click="handleResetDraw">
          <div style="text-align: center">
            <NIcon size="26">
              <ArrowReset24Filled />
            </NIcon>
            <br />
            <span style="display: inline-block">撤销</span>
          </div>
        </div>
        <div @click="handleDrawClean">
          <div style="text-align: center">
            <NIcon size="26">
              <CleaningServicesOutlined />
            </NIcon>
            <br />
            <span style="display: inline-block">清空</span>
          </div>
        </div>
      </div>
      <!-- 右侧 -->
      <div style="width: 160px;">
        <!-- :file-list="fileList" :show-file-list="false" -->
        <NUpload :max="1" action="/v1/common/upload" @before-upload="beforeUpload" @finish="handleFinish">
          <div class="upload" style="text-align: center; width: 100% !important; ">
            <NIcon size="26">
              <Images />
            </NIcon>
            <br />
            <span style="display: inline-block;">上传图片</span>
          </div>
        </NUpload>
      </div>
    </div>
    <!-- === -->
    <div id="DrawWrap">
      <canvas id="DrawCompoent" @click="handleClickCanvas"></canvas>
    </div>
  </div>
  <!-- </NSpin> -->
</template>

<style lang="scss" scoped>
#canvas-4 {
  position: fixed;
  top: -10000px;

  // width: 900px;
  // height: 900px;
}

.n-upload-file-list {
  display: none;
}

#canvas-4>canvas {
  width: 600px;
  height: 350px;
  border: 1xp solid red;
}

.draw-tool {
  height: 70px !important;
  margin: 20px 0;
  display: flex;
  padding-top: 5px;
  justify-content: space-between;
  background: #f8f8f9;
  border-radius: 10px;

  &>div {
    display: flex;
    justify-content: start;
  }

  &>div>div {
    height: 100%;
    width: 80px;
    display: flex;
    justify-content: center;
    align-items: center;
    cursor: pointer;
    font-size: 14px;
  }

  // &>div>.upload {
  //   border: 1px solid green !important;
  //   background-color: red;
  // }

}

// .upload {
//   width: 200px !important;
// }

#DrawCompoent {
  height: 100%;
  width: 100%;
  background-color: #f8f8f9;
}

#DrawWrap {
  height: 300px;
  transition: calc(2);
  position: relative;
}
</style>
