import React, { memo, useState, useEffect, useContext, createRef } from 'react';
import { Rnd } from 'components/ReactRnd';
import Mousetrap from 'mousetrap';
import styles from './Transformer.less';
import { PartialStateShare, raf } from 'utils/utils';
import { pressed, flatLayers, getCompareAlignLayers, computeAdsorbedOffset, drawSupportLine, clearSupportLines } from './Moveable';
import { ModalEditContext } from 'components/Screen/EditContext';

function Handle({ style }) {
  return (
    <div>
      <div style={{ ...style, position: 'absolute' }}></div>
    </div>
  );
}

// todo: cursor改成move
export default memo(function Transformer({
  width,
  height,
  top,
  left,
  scale,
  grid = 1,
  lockAspectRatio,
  onResizeStart,
  onResize,
  onResizeStop,
  onDragStop
}: {
  width: number;
  height: number;
  top: number;
  left: number;
  scale: number;
  grid?: number;
  lockAspectRatio?: boolean;
  onResizeStart: () => any;
  onResize: (param) => any;
  onResizeStop: (param) => any;
  onDragStop: (param) => any;
}) {
  const { canvasWidth, canvasHeight, selectedlayers, layers, components, panels, rulerLines } = useContext(ModalEditContext);
  const [nextScale, setValue] = useState({ width, height, top, left, isResizing: false });
  const [enableScale, setScale] = useState(true);
  const [shift, setShift] = useState(false);
  const resizeInstance = createRef<Rnd>();
  const movePix = {
    arrowup: {
      deltaX: 0,
      deltaY: -grid
    },
    arrowdown: {
      deltaX: 0,
      deltaY: grid
    },
    arrowleft: {
      deltaX: -grid,
      deltaY: 0
    },
    arrowright: {
      deltaX: grid,
      deltaY: 0
    }
  };
  useEffect(() => {
    setValue({ width, height, top, left, isResizing: false });

    Mousetrap.bind(['up', 'down', 'left', 'right'], function (e) {
      e.preventDefault();
      onDragStop(movePix[e.code.toLowerCase()]);
    });
    Mousetrap.bind(['shift+up', 'shift+down', 'shift+left', 'shift+right'], function (e) {
      e.preventDefault();
      const moveDis = movePix[e.code.toLowerCase()];
      onDragStop({ deltaX: moveDis.deltaX * 10, deltaY: moveDis.deltaY * 10 });
    });

    return () => {
      Mousetrap.unbind(['up', 'down', 'left', 'right']);
      Mousetrap.unbind(['shift+up', 'shift+down', 'shift+left', 'shift+right']);
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [width, height, top, left, scale, grid]);

  useEffect(() => {
    const onChange = (e) => {
      // 移动时隐藏角
      setScale(!e);
      setShift(e ? pressed({ keys: ['shift'], e }) : false);
    };
    PartialStateShare.on('simulator_drag', onChange);
    PartialStateShare.on('box_resize', onChange);
    return () => {
      PartialStateShare.off('simulator_drag', onChange);
      PartialStateShare.off('box_resize', onChange);
    };
  }, []);

  const onRndResizeStart = (e) => {
    // todo: 后面去掉
    PartialStateShare.emit('box_resize', e);
    e.stopPropagation();
    setValue({ ...nextScale, isResizing: true });
    onResizeStart();
  };

  const onRndResize = raf((e, direction, _ref, delta) => {
    e.stopPropagation();
    direction = direction.toLowerCase();
    let newWidth = width + delta.width;
    let newHeight = height + delta.height;
    let newTop = top;
    let newLeft = left;
    if (direction.indexOf('left') > -1) {
      newLeft -= delta.width;
    }
    if (direction.indexOf('top') > -1) {
      newTop -= delta.height;
    }

    if (!pressed({ e, keys: ['ctrl'] })) {
      const dragedPosition = { width: newWidth, height: newHeight, left: newLeft, top: newTop };
      const compareAlignLayers = getCompareAlignLayers({
        flatedLayers: flatLayers(layers, { ignoreLocked: false }),
        moveLayerIds: selectedlayers,
        components,
        panels,
        screen: { width: canvasWidth, height: canvasHeight }
      });
      const offset = computeAdsorbedOffset({
        box: dragedPosition,
        compareLayers: compareAlignLayers,
        scale,
        rulerLines,
        checkSides: ['left', 'right', 'top', 'bottom'].filter((d) => new RegExp(d, 'i').test(direction))
      });

      if (direction.indexOf('left') > -1) {
        newLeft += offset.left;
        newWidth -= offset.left;
      }
      if (direction.indexOf('right') > -1) {
        newWidth += offset.left;
      }
      if (direction.indexOf('top') > -1) {
        newTop += offset.top;
        newHeight -= offset.top;
      }
      if (direction.indexOf('bottom') > -1) {
        newHeight += offset.top;
      }

      drawSupportLine({
        list: compareAlignLayers,
        box: { width: newWidth, height: newHeight, left: newLeft, top: newTop },
        showHorizontal: true,
        showVertical: true,
        scale
      });
    } else {
      clearSupportLines();
    }

    setValue({ ...nextScale, width: newWidth, height: newHeight, top: newTop, left: newLeft });
    onResize({
      originX: left,
      originY: top,
      x: newLeft,
      y: newTop,
      scaleWidth: width ? newWidth / width : newWidth,
      scaleHeight: height ? newHeight / height : newHeight
    });

    // 主动更新drag的位置和尺寸
    resizeInstance.current?.updatePosition({ x: newLeft, y: newTop });
    resizeInstance.current?.updateSize({ width: newWidth, height: newHeight });
  });

  const onRndResizeStop = (e, direction, _ref, delta) => {
    PartialStateShare.emit('box_resize', false);
    e.stopPropagation();
    direction = direction.toLowerCase();
    const newWidth = width + delta.width;
    const newHeight = height + delta.height;
    let newTop = top;
    let newLeft = left;
    if (direction.indexOf('left') > -1) {
      newLeft = newLeft - delta.width;
    }
    if (direction.indexOf('top') > -1) {
      newTop = newTop - delta.height;
    }
    setValue({ ...nextScale, isResizing: false });
    onResizeStop({
      originX: left,
      originY: top,
      x: newLeft,
      y: newTop,
      scaleWidth: width ? newWidth / width : newWidth,
      scaleHeight: height ? newHeight / height : newHeight
    });
  };

  let cornResizeEnable = false;
  let verticalResizeEnable = false;
  let horizontalResizeEnable = false;
  let circleWidth = Math.floor(6 / scale);
  circleWidth = circleWidth < 6 ? 6 : circleWidth;
  // circleWidth = circleWidth > 12 ? 12 : circleWidth
  if (enableScale) {
    const maxHorizontalRectNumber = nextScale.width / circleWidth;
    const maxVerticalRectNumber = nextScale.height / circleWidth;
    cornResizeEnable = maxHorizontalRectNumber > 2 && maxVerticalRectNumber > 2;
    verticalResizeEnable = true;
    horizontalResizeEnable = true;
  }

  const spread = nextScale.width <= circleWidth * 3 || nextScale.height <= circleWidth * 3;
  const halfWidth = spread ? -circleWidth * 2 : -circleWidth / 2;
  const circle = { width: circleWidth, height: circleWidth, borderRadius: circleWidth + 'px', background: 'white' };
  const handleStyle = {
    top: <Handle style={{ ...circle, left: '50%', transform: 'translateX(-50%)' }} />,
    right: !spread ? (
      <Handle style={{ ...circle, top: '50%', transform: 'translate(-50%, -50%)' }} />
    ) : (
      <Handle style={{ ...circle, top: '50%', right: 0, transform: 'translate(0, -50%)' }} />
    ),
    bottom: !spread ? (
      <Handle style={{ ...circle, left: '50%', transform: 'translate(-50%, -50%)' }} />
    ) : (
      <Handle style={{ ...circle, left: '50%', bottom: 0, transform: 'translate(-50%, 0)' }} />
    ),
    left: <Handle style={{ ...circle, top: '50%', transform: 'translateY(-50%)' }} />
  };
  const _w = Math.floor(10 / scale);
  const cornerStyle = {
    left: { left: halfWidth },
    right: !spread ? { right: -_w, width: _w } : { right: halfWidth },
    top: { top: halfWidth },
    bottom: !spread ? { bottom: -_w, height: _w } : { bottom: halfWidth },
    bottomLeft: { ...circle, left: halfWidth, bottom: halfWidth },
    bottomRight: { ...circle, right: halfWidth, bottom: halfWidth },
    topLeft: { ...circle, left: halfWidth, top: halfWidth },
    topRight: { ...circle, right: halfWidth, top: halfWidth }
  };

  return (
    <div className={styles.container}>
      <Rnd
        ref={resizeInstance}
        id={'transformer_box'}
        size={{ width: nextScale.width, height: nextScale.height }}
        position={{ x: nextScale.left === undefined ? -9999 : nextScale.left, y: nextScale.top === undefined ? -9999 : nextScale.top }}
        scale={scale}
        disableDragging={true}
        lockAspectRatio={shift || lockAspectRatio}
        resizeHandleWrapperClass={styles.resizeWrap}
        enableResizing={{
          bottom: verticalResizeEnable,
          bottomLeft: cornResizeEnable,
          bottomRight: cornResizeEnable,
          left: horizontalResizeEnable,
          right: horizontalResizeEnable,
          top: verticalResizeEnable,
          topLeft: cornResizeEnable,
          topRight: cornResizeEnable
        }}
        resizeHandleStyles={cornerStyle}
        resizeHandleComponent={handleStyle}
        onResizeStart={onRndResizeStart}
        onResize={onRndResize}
        onResizeStop={onRndResizeStop}
        style={{ zIndex: 3, cursor: 'move' }}>
        <div className={styles.content}>
          <span
            className={styles.line}
            style={{ top: 0, left: 0, width: 1, height: '100%', transform: `translate(-50%, 0) scaleX(${1 / scale})` }}
          />
          <span
            className={styles.line}
            style={{ top: 0, right: 0, width: 1, height: '100%', transform: `translate(50%, 0) scaleX(${1 / scale})` }}
          />
          <span
            className={styles.line}
            style={{ top: 0, left: 0, width: '100%', height: 1, transform: `translate(0, -50%) scaleY(${1 / scale})` }}
          />
          <span
            className={styles.line}
            style={{ bottom: 0, left: 0, width: '100%', height: 1, transform: `translate(0, 50%) scaleY(${1 / scale})` }}
          />
        </div>
      </Rnd>
      {nextScale.isResizing && <Signal {...nextScale} scale={scale} />}
    </div>
  );
});

function Signal({ left, top, width, height, scale }) {
  return (
    <div
      style={{
        position: 'absolute',
        left: left + width,
        top: top + height,
        background: 'rgba(0,0,0,0.5)',
        color: '#fff',
        padding: '4px 6px',
        whiteSpace: 'nowrap',
        transform: `scale(${1 / scale}) translate(${40 * scale}px, 0px)`,
        transformOrigin: 'top left'
      }}>
      {width} x {height}
    </div>
  );
}
