import React, { useEffect, useContext } from 'react';
import { arrayExpand } from 'utils/data-helper';
import { getGroupDimension, componentOperator } from 'utils/component';
import { PartialStateShare, raf, isGroup } from 'utils/utils';
import style from './Moveable.less';
import { ModalEditContext } from 'components/Screen/EditContext';

// todo: 检查结束拖拽有延迟

// 屏幕坐标转换成canvas画布内位置
export const getCoordinateInBoard = (screen) => {
  const { x, y } = document.getElementById('m-simulator-container')?.getBoundingClientRect() || { x: 0, y: 0 };
  const scale = (PartialStateShare.get('simulator_scale') as number) || 1;
  return { x: (screen.x - x) / scale, y: (screen.y - y) / scale };
};

// 检查是否忽略图层
export function layerIgnored(layer, option: { ignoreInvisible?: boolean; ignoreLocked?: boolean; ignoreGroup?: boolean } = {}) {
  const ignoreLocked = 'ignoreLocked' in option ? option.ignoreLocked : true;
  const ignoreInvisible = 'ignoreInvisible' in option ? option.ignoreInvisible : true;
  const ignoreGroup = 'ignoreGroup' in option ? option.ignoreGroup : false;
  if (!layer) return true;
  if (ignoreLocked && layer.lock) return true;
  if (ignoreInvisible && !layer.show) return true;
  if (ignoreGroup && isGroup(layer.id)) return true;
  return false;
}

interface ContainedType {
  top: number;
  left: number;
  width: number;
  height: number;
}
// 检查child是否完全包含在parent内
export const contained = (child: ContainedType, parent: ContainedType) => {
  return (
    parent.left <= child.left &&
    parent.top <= child.top &&
    parent.left + parent.width >= child.left + child.width &&
    parent.top + parent.height >= child.top + child.height
  );
};

// 按照从上往下的顺序 拉平图层的结构
export const flatLayers = (layers, option?) => {
  const list: any = [];
  arrayExpand(
    layers,
    (layer) => (layer.components ? layer.components.map((n) => ({ ...n, parent: { ...layer } })) : undefined),
    (layer) => {
      if (layerIgnored(layer, option)) return false;
      list.push(layer);
    }
  );
  return list;
};

// 计算hovered图层
export function getHoverLayer(hoverLayers, flattedLayers, selectedLayers, commandPressed) {
  if (!hoverLayers.length) return null;

  // 按下command时 排除group图层进行选择
  if (commandPressed) {
    return hoverLayers.find((layer) => !isGroup(layer.id));
  }

  // 加入黑名单的id
  const blackList = new Set();
  // 图层是否置顶显示
  const layerStick = JSON.parse(localStorage.getItem('layerStick') || 'false');

  if (selectedLayers.length) {
    // 开启功能：选中图层(即使被盖住)可以直接拖拽
    if (layerStick) {
      const topLayers = hoverLayers.filter((layer) => ~selectedLayers.indexOf(layer.id));
      hoverLayers = topLayers.concat(hoverLayers);
    }

    flattedLayers.map((layer) => {
      if (~selectedLayers.indexOf(layer.id)) {
        if (layer.parent) {
          let _item = layer;
          while (_item.parent) {
            blackList.add(_item.parent.id);
            _item = _item.parent;
          }
        }
      }
    });
  }

  return hoverLayers.find((layer) => {
    if (blackList.has(layer.id)) return;
    return true;
  });
}

// 获取按键状态
export const pressed = ({ keys, only, e }: { keys: any[]; only?: boolean; e: any }) => {
  const isWindow = ~window.navigator.userAgent.indexOf('Windows');
  const status = { alt: e.altKey, ctrl: isWindow ? e.ctrlKey : e.metaKey, shift: e.shiftKey };
  if (only) {
    return Object.keys(status).every((key) => {
      if (~keys.indexOf(key)) return status[key];
      return !status[key];
    });
  }
  return keys.every((key) => status[key]);
};

// shift键 按下后是否有起效果
const shiftActived = (shiftPress, offsetX, offsetY) => {
  if (shiftPress) {
    if (Math.abs(offsetX) >= Math.abs(offsetY)) {
      offsetY = 0;
    } else {
      offsetX = 0;
    }
  }
  return { offsetX: Math.round(offsetX), offsetY: Math.round(offsetY) };
};

// 返回最靠近的一组 由a和b组成
function getClosestPair(a, b) {
  let min: number | null = null;
  let value = 0;
  let aIndex = null;
  let bIndex = null;
  a.map((v, ai) => {
    b.map((v1, bi) => {
      const vx = Math.abs(v - v1); //获取绝对值
      if (min === null || vx < min) {
        min = vx;
        value = v1 - v;
        aIndex = ai;
        bIndex = bi;
      }
    });
  });

  return { min, value, a: aIndex, b: bIndex };
}

// 返回图层的六根线
function getInfo({ left, top, width, height }) {
  return {
    left,
    top,
    width,
    height,
    h1: top,
    h2: top + Math.ceil(height / 2), //水平中线
    h3: top + height,
    v1: left,
    v2: left + Math.ceil(width / 2), // 垂直中线
    v3: left + width
  };
}

// 计算吸附后位置偏移
export const computeAdsorbedOffset = ({
  box,
  compareLayers,
  scale,
  rulerLines,
  checkSides
}: {
  box: any;
  compareLayers: any[];
  scale: number;
  rulerLines: any;
  checkSides?: any;
}) => {
  // 贴边逻辑：
  // 排除掉拖动元素
  // 拿到其他元素的6条线
  // 拿拖拽对象的水平3根线对所有的组件的水平线去比较拿到最小距离
  // 拿拖拽对象的垂直3根线对所有的组件的垂直线去比较拿到最小距离
  // 如果 最小距离>5 则忽略
  // 如果有最小距离 修改拖拽对象的left，top匹配对应线的值

  // 辅助线展示逻辑：
  // 找到所有水平3跟线跟 拖拽对象A的水平3根线 相等的数组列表 然后计算出左到右2端位置
  // 找到所有垂直3跟线跟 拖拽对象A的垂直3根线 相等的数组列表 然后计算出上到下2端位置

  // 距离展示逻辑：
  // 如果有辅助线的情况下 找到水平方向最接近A的对象
  // 如果有辅助线的情况下 找到垂直方向最接近A的对象

  const { left, top, width, height } = box;

  const list = compareLayers;
  const rulerHorizontalLines = (rulerLines || {}).v || [];
  const rulerVerticalLines = (rulerLines || {}).h || [];
  const beDragger = getInfo({ left, top, width, height });

  const beDraggerHs = [beDragger.h1, beDragger.h2, beDragger.h3];
  if (checkSides) {
    ~checkSides.indexOf('top') && beDraggerHs.push(beDragger.h1);
    ~checkSides.indexOf('bottom') && beDraggerHs.push(beDragger.h3);
  }
  const beDraggerVs = [beDragger.v1, beDragger.v2, beDragger.v3];
  if (checkSides) {
    ~checkSides.indexOf('left') && beDraggerHs.push(beDragger.v1);
    ~checkSides.indexOf('right') && beDraggerHs.push(beDragger.v3);
  }
  const minDistance = 5 / scale;
  let minHorizontalDistanceLayer: any = null;
  let minVerticalDistanceLayer: any = null;
  // 对齐其他图层
  list.map((item) => {
    const hs = [item.h1, item.h2, item.h3];
    {
      if (beDraggerHs.length) {
        const { min, value } = getClosestPair(beDraggerHs, hs);
        const minNum: number = min || 0;
        if (minNum <= minDistance && (minHorizontalDistanceLayer === null || minNum < minHorizontalDistanceLayer.min)) {
          minHorizontalDistanceLayer = { min, value };
        }
      }
    }
    {
      if (beDraggerVs) {
        const { min, value } = getClosestPair(beDraggerVs, [item.v1, item.v2, item.v3]);
        const minNum: number = min || 0;
        if (minNum <= minDistance && (minVerticalDistanceLayer === null || minNum < minVerticalDistanceLayer.min)) {
          minVerticalDistanceLayer = { min, value };
        }
      }
    }
  });
  // 对齐标尺线
  // 水平方向
  rulerHorizontalLines.map((t) => {
    if (!beDraggerHs.length) return;
    const { min, value } = getClosestPair(beDraggerHs, [t]);
    const minNum: number = min || 0;
    if (minNum <= minDistance && (minHorizontalDistanceLayer === null || minNum < minHorizontalDistanceLayer.min)) {
      minHorizontalDistanceLayer = { min, value };
    }
  });

  // 垂直方向
  rulerVerticalLines.map((l) => {
    if (!beDraggerVs.length) return;
    const { min, value } = getClosestPair(beDraggerVs, [l]);
    const minNum: number = min || 0;
    if (minNum <= minDistance && (minVerticalDistanceLayer === null || minNum < minVerticalDistanceLayer.min)) {
      minVerticalDistanceLayer = { min, value };
    }
  });

  return {
    top: minHorizontalDistanceLayer ? minHorizontalDistanceLayer.value : 0,
    left: minVerticalDistanceLayer ? minVerticalDistanceLayer.value : 0
  };
};

// create line element
function createLine({
  left,
  top,
  len,
  isVertical,
  showDistance,
  originLine,
  scale
}: {
  left: number;
  top: number;
  len: number;
  isVertical?: boolean;
  showDistance?: boolean;
  originLine?: boolean;
  scale: number;
}) {
  len = len * scale;
  left = left * scale;
  top = top * scale;
  const line = document.createElement('div') as HTMLElement;
  line.classList.add(style.support_line);
  line.classList.add(isVertical ? style['support_line--vertical'] : style['support_line--horizontal']);

  line.style.left = left + 'px';
  line.style.top = top + 'px';
  if (isVertical) {
    line.style.height = len + 'px';
  } else {
    line.style.width = len + 'px';
  }

  // 原点线
  if (originLine) {
    line.classList.add(style['support_line--white']);
  }
  // 显示距离数字
  if (showDistance) {
    line.classList.add(isVertical ? style['distance_line--vertical'] : style['distance_line--horizontal']);
    line.textContent = '' + Math.round(len);
  }
  return line;
}

// 计算和绘制辅助性
// box = {width, height, top, left}
export const drawSupportLine = ({ list, box, showHorizontal, showVertical, scale }) => {
  // 用新的拖拽位置计算
  const tinfo = getInfo(box);
  const hs = [tinfo.h1, tinfo.h2, tinfo.h3],
    vs = [tinfo.v1, tinfo.v2, tinfo.v3];
  const nhs: any = [], // 水平3条线的左右2端位置数组[[],[],[]]
    nvs: any = [], // 垂直3条线的上下2端位置数组[[],[],[]]
    dds: any = []; // 4个方向要展示的距离 [top,right,bottom,left]

  // 计算辅助线
  list.map((item) => {
    if (showVertical) {
      const list = [item.h1, item.h2, item.h3];
      hs.map((h, i) => {
        if (~list.indexOf(h)) {
          if (!nhs[i]) {
            nhs[i] = [Math.min(item.v1, tinfo.v1), Math.max(item.v3, tinfo.v3)];
          } else {
            nhs[i] = [Math.min(item.v1, nhs[i][0]), Math.max(item.v3, nhs[i][1])];
          }

          const toLeft = tinfo.v1 - item.v3;
          if (toLeft >= 0 && (!dds[3] || toLeft < dds[3].d)) {
            dds[3] = { d: toLeft, top: h, left: item.v3 };
          }
          const toRight = item.v1 - tinfo.v3;
          if (toRight >= 0 && (!dds[1] || toRight < dds[1].d)) {
            dds[1] = { d: toRight, top: h, left: tinfo.v3 };
          }
        }
      });
    }
    if (showHorizontal) {
      const list = [item.v1, item.v2, item.v3];
      vs.map((v, i) => {
        if (~list.indexOf(v)) {
          if (!nvs[i]) {
            nvs[i] = [Math.min(item.h1, tinfo.h1), Math.max(item.h3, tinfo.h3)];
          } else {
            nvs[i] = [Math.min(item.h1, nvs[i][0]), Math.max(item.h3, nvs[i][1])];
          }

          const toTop = tinfo.h1 - item.h3;
          if (toTop >= 0 && (!dds[0] || toTop < dds[0].d)) {
            dds[0] = { d: toTop, top: item.h3, left: v, isVertical: true };
          }
          const toBottom = item.h1 - tinfo.h3;
          if (toBottom >= 0 && (!dds[2] || toBottom < dds[2].d)) {
            dds[2] = { d: toBottom, top: tinfo.h3, left: v, isVertical: true };
          }
        }
      });
    }
  });

  // 开始画线
  const fragment = document.createDocumentFragment();
  hs.map((h, i) => {
    const range = nhs[i];
    if (!range) return;
    // 如果顶线和底线对齐另一个组件 忽略中线
    if (i === 1 && (nhs[0] || nhs[2])) return;
    fragment.appendChild(createLine({ left: range[0], top: h, len: range[1] - range[0], scale }));
  });
  vs.map((v, i) => {
    const range = nvs[i];
    if (!range) return;
    // 如果左线和右线对齐另一个组件 忽略中线
    if (i === 1 && (nvs[0] || nvs[2])) return;
    fragment.appendChild(createLine({ isVertical: true, left: v, top: range[0], len: range[1] - range[0], scale }));
  });
  // 显示距离（距离最近的对齐元素, 忽略距离为0元素
  dds.map(({ d, top, left, isVertical }) => {
    d && fragment.appendChild(createLine({ isVertical, left, top, len: d, showDistance: true, scale }));
  });
  // 距离原点(0,0)的距离显示
  fragment.appendChild(createLine({ left: 0, top: tinfo.top, len: tinfo.left, originLine: true, scale }));
  fragment.appendChild(createLine({ isVertical: true, left: tinfo.left, top: 0, len: tinfo.top, originLine: true, scale }));
  const text = document.createElement('div');
  text.className = style.origin_coordinate;
  text.textContent = `${tinfo.left}, ${tinfo.top}`;
  text.style.left = tinfo.left * scale + 'px';
  text.style.top = tinfo.top * scale + 'px';
  fragment.appendChild(text);

  if (supportLineEl) {
    supportLineEl.innerHTML = '';
    supportLineEl.appendChild(fragment);
  }
};
// 清除辅助线
export const clearSupportLines = () => {
  if (supportLineEl) supportLineEl.innerHTML = '';
};

// 计算需要对齐的图层列表
// 规则：
// 1. 只取同个层级的图层进行比较（如果同层级有分组，将其当成一个整体
// 2. 如果选中多个图层他们处于不同层级 将这些层级都加上
// 3. 排除选中图层
// 4. 如果选中图层包含根级，加一个整个画布大小的图层(用来对齐画布的6条线)
export function getCompareAlignLayers({ flatedLayers, moveLayerIds, components, panels, screen }) {
  const selectedGrade = new Set();
  flatedLayers
    .filter((layer) => ~moveLayerIds.indexOf(layer.id))
    .forEach((layer) => selectedGrade.add(layer.parent ? layer.parent.id : 'root'));

  const list = flatedLayers
    .filter((layer) => {
      // 排除拖动的图层和隐藏的图层
      if (~moveLayerIds.indexOf(layer.id) || layerIgnored(layer, { ignoreLocked: false })) return false;
      if (!layer.parent && selectedGrade.has('root')) return true;
      if (layer.parent && selectedGrade.has(layer.parent.id)) return true;
    })
    .map((layer) => getInfo(componentOperator.getLayerScale({ layer, componentsById: components, panelsById: panels })));
  list.push(getInfo({ left: 0, top: 0, width: screen.width, height: screen.height }));

  return list;
}

// 鼠标移动
export function MouseHover() {
  const { canvasWidth, canvasHeight, layers, selectedlayers, components, panels ,rulerLines} = useContext(ModalEditContext);
  useEffect(() => {
    let boxs: any[] = []; // 拖拽图层列表
    let startX: number | null = 0;
    let startY: number | null = 0;
    let startArea: any = null; // 开始拖拽时 整个拖拽区域的位置范围信息
    let endArea: any = null; // 结束拖拽时 整个拖拽区域的位置范围信息
    let flatedLayers: any[] = [];
    let compareAlignLayers: any[] = [];

    function MouseHoveComponentRuler ({el:e,hover}){
      // 当 按下 option 或者 alt 时，当前hover 组件距离选中组件的标尺提示。

       startX = e.clientX;
       startY = e.clientY;
  
       flatedLayers = flatLayers(layers, { ignoreLocked: false });
       boxs = flatedLayers
         .filter((layer: any) => layer.id == hover.id)
         .map((layer) => ({ ...componentOperator.getLayerScale({ layer, componentsById: components, panelsById: panels }), layer }));
 
      // resizebox: 如果图层没被选中 则给予选择状态
      if (!startArea) {
        startArea = getGroupDimension(boxs);
        endArea = { ...startArea };
      }

      compareAlignLayers = getCompareAlignLayers({
        flatedLayers,
        moveLayerIds:[hover.id],
        components,
        panels,
        screen: { width: canvasWidth, height: canvasHeight }
      });

      const scale = PartialStateShare.get('simulator_scale') || 1;
      const { offsetX, offsetY } = shiftActived(e.shiftKey, (e.clientX - startX) / scale, (e.clientY - startY) / scale);

      const dragedPosition = { ...startArea, left: startArea.left + offsetX, top: startArea.top + offsetY };
      const offset = computeAdsorbedOffset({ box: dragedPosition, compareLayers: compareAlignLayers, scale, rulerLines });
      endArea = { ...dragedPosition, left: dragedPosition.left + offset.left, top: dragedPosition.top + offset.top };
      drawSupportLine({ list: compareAlignLayers, box: endArea, showHorizontal: true, showVertical: true, scale });

      PartialStateShare.emit('simulator_dragging', { event: e, ...startArea });
    }
    const onmousemove = (e) => {
      const { x, y } = getCoordinateInBoard({ x: e.clientX, y: e.clientY });

      // 拖拽期间禁用hover
      if (PartialStateShare.get('simulator_drag') || PartialStateShare.get('box_resize')) return;

      const flattedLayers = flatLayers(layers);
      const overlapLayers = flattedLayers.filter((layer) =>
        contained(
          { left: x, top: y, width: 0, height: 0 },
          componentOperator.getLayerScale({ layer, componentsById: components, panelsById: panels })
        )
      );
      const hover = getHoverLayer(overlapLayers, flattedLayers, selectedlayers, pressed({ e, keys: ['ctrl'] }));
      if( pressed({ e, keys: ['alt'] }) && hover && selectedlayers.length && !selectedlayers.includes(hover.id)){
        MouseHoveComponentRuler({
          el:e,
          hover
        })
      }else{
        // clear ruler
        onClearSupportLines();
      }
      PartialStateShare.emit('mouse_over_layer', { hover: hover ? hover.id : null });
    };
    const onClearSupportLines = ()=>{
      clearSupportLines();
      boxs = [];
      startX = null;
      startY = null;
      startArea = endArea = null;
    }
    PartialStateShare.on('simulator_mousemove', onmousemove);
    PartialStateShare.on('simulator_keyup', onClearSupportLines);
    PartialStateShare.on('simulator_keydown', onmousemove);
    return () => {
      PartialStateShare.off('simulator_mousemove', onmousemove);
      PartialStateShare.off('simulator_keyup', onClearSupportLines);
      PartialStateShare.off('simulator_keydown', onmousemove);
    };
  }, [layers, selectedlayers, components, panels]);
  return <div />;
}

let supportLineEl;
// 鼠标拖拽
export function MouseDrag({ onDragEnd }) {
  const { canvasWidth, canvasHeight, selectedlayers, layers, components, panels, rulerLines } = useContext(ModalEditContext);
  useEffect(() => {
    supportLineEl = document.getElementById('support_lines');
  }, []);
  useEffect(() => {
    let boxs: any[] = []; // 拖拽图层列表
    let startX: number | null = null;
    let startY: number | null = null;
    let copy = false; //拖拽复制
    let changeLayer: number | string | null = null; // 标记新选择图层id
    let moveLayerIds: any = null; // 进行移动的图层id
    let resizeEl: any = null; // 整体外框
    let startArea: any = null; // 开始拖拽时 整个拖拽区域的位置范围信息
    let endArea: any = null; // 结束拖拽时 整个拖拽区域的位置范围信息
    let moveStarted = false;
    let flatedLayers: any[] = [];
    let compareAlignLayers: any[] = [];

    const onmousedown = (e) => {
      const mouseOnLayer = (PartialStateShare.get('mouse_over_layer') || {}).hover;
      const spacePressed = PartialStateShare.get('space_press');

      const altPressed = pressed({ e, keys: ['alt'] });
      const ctrlAltPress = pressed({ e, keys: ['ctrl', 'alt'] });

      // 按下alt 拖动复制
      // 按下ctrl+alt 只拖动选中图层 鼠标在任何位置都能拖动
      if (e.buttons !== 1 || spacePressed) return;
      copy = !ctrlAltPress && altPressed;

      startX = e.clientX;
      startY = e.clientY;

      if (mouseOnLayer && !ctrlAltPress) {
        if (~selectedlayers.indexOf(mouseOnLayer)) {
          // 鼠标所在图层被选中
          moveLayerIds = selectedlayers;
        } else {
          // 鼠标所在图层未被选中
          changeLayer = mouseOnLayer;
          moveLayerIds = [mouseOnLayer];
        }
      } else if (selectedlayers.length && ctrlAltPress) {
        moveLayerIds = selectedlayers;
      }
      resizeEl = document.getElementById('transformer_box');
      if (!moveLayerIds) {
        return;
      }

      flatedLayers = flatLayers(layers, { ignoreLocked: false });
      boxs = flatedLayers
        .filter((layer: any) => ~moveLayerIds.indexOf(layer.id))
        .map((layer) => ({ ...componentOperator.getLayerScale({ layer, componentsById: components, panelsById: panels }), layer }));

      // 按下alt
      if (copy) {
        const fragment = document.createDocumentFragment();
        boxs.forEach((scale) => {
          const { left, top, width, height } = scale;
          const div = document.createElement('div');
          div.style.width = width + 'px';
          div.style.height = height + 'px';
          div.style.top = top + 'px';
          div.style.left = left + 'px';
          div.style.position = 'absolute';
          div.style.border = '1px solid #2491f7';
          div.style.background = 'rgba(0, 132, 255, 0.15)';
          div.style.opacity = '0.8';
          scale.el = div;
          fragment.appendChild(div);
        });
        const simulator = document.getElementById('m-simulator');
        simulator?.appendChild(fragment);
        return;
      }

      // 没按下alt
      boxs.forEach((box) => (box.el = document.getElementById(`rnd_${box.id}`)));
    };
    const onmousemove = raf((e) => {
      if (!boxs.length) return;

      if (startX === null || startY === null) {
        return;
      }

      if (PartialStateShare.get('box_resize')) {
        onmouseup();
        return;
      }

      if (!moveStarted) {
        // 防止点击
        if (Math.abs(e.clientX - startX) <= 1 && Math.abs(e.clientY - startY) <= 1) return;

        PartialStateShare.emit('simulator_drag', e);

        if (!copy) {
          // 去掉selected状态
          if (changeLayer) {
            selectedlayers.forEach((id) => {
              const el = document.getElementById('rnd_' + id);
              el && el.classList.remove('selected');
            });
          }
        }

        // resizebox: 如果图层没被选中 则给予选择状态
        if (!startArea) {
          startArea = getGroupDimension(boxs);
          endArea = { ...startArea };
        }

        if (!pressed({ e, keys: ['ctrl'] })) {
          compareAlignLayers = getCompareAlignLayers({
            flatedLayers,
            moveLayerIds,
            components,
            panels,
            screen: { width: canvasWidth, height: canvasHeight }
          });
        }

        const { width, height, left, top } = startArea;
        resizeEl.style.width = width + 'px';
        resizeEl.style.height = height + 'px';
        resizeEl.style.left = left + 'px';
        resizeEl.style.top = top + 'px';
        resizeEl.style.display = 'block';

        PartialStateShare.emit('simulator_dragging', { event: e, layers: flatedLayers, ...startArea });
        moveStarted = true;
        return;
      }

      const scale = PartialStateShare.get('simulator_scale') || 1;
      const { offsetX, offsetY } = shiftActived(e.shiftKey, (e.clientX - startX) / scale, (e.clientY - startY) / scale);
      // 计算贴边后(整个拖拽区域)的位置信息
      // 更新拖拽区域位置信息
      // 按下command取消吸附
      if (!pressed({ e, keys: ['ctrl'] })) {
        const dragedPosition = { ...startArea, left: startArea.left + offsetX, top: startArea.top + offsetY };
        const offset = computeAdsorbedOffset({ box: dragedPosition, compareLayers: compareAlignLayers, scale, rulerLines });
        endArea = { ...dragedPosition, left: dragedPosition.left + offset.left, top: dragedPosition.top + offset.top };
        drawSupportLine({ list: compareAlignLayers, box: endArea, showHorizontal: true, showVertical: true, scale });
      } else {
        clearSupportLines();
        endArea.left = startArea.left + offsetX;
        endArea.top = startArea.top + offsetY;
      }
      boxs.forEach((box) => {
        box.el.style.left = box.left - startArea.left + endArea.left + 'px';
        box.el.style.top = box.top - startArea.top + endArea.top + 'px';
      });

      if (!copy) {
        resizeEl.style.left = endArea.left + 'px';
        resizeEl.style.top = endArea.top + 'px';
      }

      PartialStateShare.emit('simulator_dragging', { event: e, ...startArea });
    });
    const onmouseup = function MouseDragMouseUp() {
      if (boxs.length && moveStarted && endArea) {
        PartialStateShare.emit('simulator_drag', false);
        const simulator = document.getElementById('m-simulator');
        copy && boxs.forEach(({ el }) => simulator?.removeChild(el));
        const offsetX = endArea.left - startArea.left;
        const offsetY = endArea.top - startArea.top;
        if (Math.abs(offsetX) > 2 || Math.abs(offsetY) > 2) {
          onDragEnd({
            altPress: copy,
            offsetX: offsetX,
            offsetY: offsetY,
            changeLayer,
            moveLayers: boxs.map((item) => item.id)
          });
        }
      }
      clearSupportLines();
      boxs = [];
      startX = null;
      startY = null;
      startArea = endArea = null;
      changeLayer = null;
      moveLayerIds = null;
      moveStarted = false;
    };

    PartialStateShare.on('simulator_mousedown', onmousedown);
    PartialStateShare.on('simulator_mousemove', onmousemove);
    PartialStateShare.on('simulator_mouseup', onmouseup);
    return () => {
      onmousemove && onmousemove.destory();
      PartialStateShare.off('simulator_mousedown', onmousedown);
      PartialStateShare.off('simulator_mousemove', onmousemove);
      PartialStateShare.off('simulator_mouseup', onmouseup);
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [canvasWidth, canvasHeight, selectedlayers, layers, components, panels, rulerLines]);
  return null;
}

// 区域框选组件
export function BoxSelection({ onChange }) {
  useEffect(() => {
    let box: HTMLElement | null;
    let startX: number | null;
    let startY: number | null;
    let canvasX: number;
    let canvasY: number;
    let drawBox = false;

    const onmousedown = (e) => {
      const hoverId = (PartialStateShare.get('mouse_over_layer') || {}).hover;
      const mousePress = PartialStateShare.get('mouse_press');
      const spacePress = PartialStateShare.get('space_press');
      const ctrlPress = pressed({ e, keys: ['ctrl'] });
      const altPress = pressed({ e, keys: ['alt'] });
      const shiftPress = pressed({ e, keys: ['shift'] });

      // 左键点击 && 点击空白处 && 按键未按下 && 鼠标按下
      if (e.buttons === 1 && !hoverId && !spacePress && !ctrlPress && !altPress && !shiftPress && mousePress) {
        startX = e.clientX;
        startY = e.clientY;

        box = document.createElement('div');
        box.style.cssText =
          'position:absolute;width:0px;height:0px;font-size:0px;margin:0px;padding:0px;border:1px solid #2491f7;background:rgba(0, 132, 255, 0.15);z-index:1000;opacity:0.6;';
        box.style.left = startX + 'px';
        box.style.top = startY + 'px';
        box.style.pointerEvents = 'none';
        box.style.display = 'none';

        const { x, y } = document.getElementById('m-simulator-container')?.getBoundingClientRect() || { x: 0, y: 0 };
        canvasX = x;
        canvasY = y;
        document.body.appendChild(box);
      }
    };

    const onmousemove = raf((e) => {
      if (box) {
        if (PartialStateShare.get('box_resize') || PartialStateShare.get('simulator_drag')) {
          onmouseup();
          return;
        }

        if (startX == null || startY == null) {
          return;
        }

        const width = Math.abs(e.clientX - startX);
        const height = Math.abs(e.clientY - startY);
        const left = Math.min(startX, e.clientX);
        const top = Math.min(e.clientY, startY);

        if (!drawBox) {
          // 为了避免在drag之前出现框
          setTimeout(() => {
            if (box) {
              box.style.display = 'block';
              drawBox = true;
            }
          }, 50);
        }
        if (drawBox) {
          box.style.left = left + 'px';
          box.style.top = top + 'px';
          box.style.width = width + 'px';
          box.style.height = height + 'px';

          const scale = PartialStateShare.get('simulator_scale') || 1;
          onChange && onChange({ x: (left - canvasX) / scale, y: (top - canvasY) / scale, width: width / scale, height: height / scale });
        }
      }
    });

    const onmouseup = function BoxSelectionMouseUp() {
      if (!box) return;
      box && box?.parentNode?.removeChild(box);
      box = null;
      startX = null;
      startY = null;
      drawBox = false;
    };

    PartialStateShare.on('simulator_mousedown', onmousedown);
    PartialStateShare.on('simulator_mousemove', onmousemove);
    PartialStateShare.on('simulator_mouseup', onmouseup);

    return () => {
      onmouseup();
      onmousemove && onmousemove.destory();
      PartialStateShare.off('simulator_mousedown', onmousedown);
      PartialStateShare.off('simulator_mousemove', onmousemove);
      PartialStateShare.off('simulator_mouseup', onmouseup);
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);
  return null;
}
