import React from 'react';
import './index.less';
import Loading from '@/loading';
import { getDvaApp } from 'umi';

const app = getDvaApp();

const defaultOptions: GT.IPageOptions = {
  limit: true,
  drag: true,
  zoom: true,
  minWidth: 340,
  minHeight: 200,
  header: true,
  background: true,
  left: '0px',
  top: '0px',
  width: '800px',
  height: '100%',
  name: '金科环境',
};

interface IDragProps {
  options: GT.IPageOptions;
  router: any;
  id: number;
  onActive: Function;
}

class DragComponent extends React.PureComponent<any> {
  state = {
    mask: true,
  };
  width = 0;
  height = 0;
  // newWidth = 0;
  // newHeight = 0;
  distanceX = 0;
  distanceY = 0;
  tx = 0;
  ty = 0;
  startX = 0;
  startY = 0;
  maxWidth: number = 0;
  maxHeight: number = 0;
  targetRef: any;
  options: GT.IPageOptions;
  newWidth: any;
  newHeight: any;

  constructor(props: IDragProps) {
    super(props);
    // this.myRef = React.createRef();
    this.targetRef = React.createRef();
    this.options = Object.assign({}, defaultOptions, props.options);
    this.handleMouseUp = this.handleMouseUp.bind(this);
    this.handleMousedown = this.handleMousedown.bind(this);
    this.onDrag = this.onDrag.bind(this);

    document.addEventListener('mouseup', this.handleMouseUp);
  }
  componentDidMount() {
    this.init();
  }
  componentWillUnmount() {
    document.removeEventListener('mouseup', this.handleMouseUp);
  }
  // 初始化
  init() {
    const options = this.options;
    let style = this.targetRef.current.style;
    if (options.background) {
      style.backgroundColor = options.background;
    }
    this.getBoundary();
    // const {availWidth,availHeight} = window.screen
    if (!options.header) {
      style.width = this.getPxDistance('100%', this.maxWidth);
      style.height = this.getPxDistance('100%', this.maxHeight);
      style.paddingTop = 0;
    } else {
      style.width = this.getPxDistance(options.width || '', this.maxWidth);
      style.height = this.getPxDistance(options.height || '', this.maxHeight);
      style.top = this.getPxDistance(options.top || '', this.maxHeight);
      // style.right = options.right;
      if (options.right !== undefined) {
        let rightStr: string = this.getPxDistance(options.right, this.maxWidth);
        // 获得与右边距离
        let right: number = parseFloat(rightStr);
        // 获得当前盒子宽度
        let tempWidth = parseFloat(style.width);
        // 计算与左边距离
        style.left = this.maxWidth - right - tempWidth + 'px';
        delete options.right;
      } else {
        style.left = this.getPxDistance(options.left || '', this.maxWidth);
      }
    }
  }
  handleMouseUp() {
    document.onmousemove = null;
    this.setState({
      mask: false,
    });
  }
  // 将距离统一转化为px
  getPxDistance(distance: number | string, maxDistance?: number): string {
    if (typeof distance == 'number') {
      return distance + 'px';
    } else if (typeof distance == 'string' && maxDistance) {
      if (distance.includes('px')) return distance;
      if (distance.includes('%')) {
        let number = parseFloat(distance);
        number = parseInt((number * maxDistance) / 100 + '');
        return number + 'px';
      }
    }
    return '';
  }
  // 获取父元素的宽高
  getBoundary() {
    // const parentNode = this.targetRef.current.parentNode;
    // this.maxWidth = parentNode.clientWidth;
    // this.maxHeight = parentNode.clientHeight;

    this.maxWidth = window.innerWidth;
    this.maxHeight = window.innerHeight;
  }
  // 获取自身起始信息
  getInfo(e: React.MouseEvent) {
    const target = this.targetRef.current;
    this.width = target.clientWidth;
    this.height = target.clientHeight;
    let top = target.style.top;
    let left = target.style.left;
    this.tx = left.replace('px', '') * 1;
    this.ty = top.replace('px', '') * 1;
    this.startX = e.clientX;
    this.startY = e.clientY;
  }
  handleMousedown() {
    const { onActive } = this.props;
    this.setState({
      mask: true,
    });
    // let style = this.targetRef.current.style;
    onActive?.();
  }
  onDrag(event: React.MouseEvent) {
    this.getInfo(event);
    let style = this.targetRef.current.style;
    document.onmousemove = (e) => {
      if (this.options.limit) {
        this.distanceX = Math.max(
          0,
          Math.min(
            this.tx + e.clientX - this.startX,
            this.maxWidth - this.width,
          ),
        );
        this.distanceY = Math.max(
          0,
          Math.min(
            this.ty + e.clientY - this.startY,
            this.maxHeight - this.height,
          ),
        );
      } else {
        this.distanceX = this.tx + e.clientX - this.startX;
        this.distanceY = this.ty + e.clientY - this.startY;
      }
      style.left = this.distanceX + 'px';
      style.top = this.distanceY + 'px';
    };
  }
  zoomOut(e: React.MouseEvent) {
    let style = this.targetRef.current.style;
    e.stopPropagation();
    // this.startX = 0;
    // this.startY = 0;
    // this.tx = 0;
    // this.ty = 0;
    // style.top = '0px';
    // style.left = '0px';
    // style.width = this.options.minWidth + 'px';
    // style.height = this.options.minHeight + 'px';

    this.props.zoomOut?.({
      ...this.options,
      width: style.width,
      height: style.height,
      left: style.left,
      top: style.top,
    });
  }
  zoomIn(e: React.MouseEvent) {
    let style = this.targetRef.current.style;
    e.stopPropagation();
    style.width = '100%';
    style.height = '100%';
    this.startX = 0;
    this.startY = 0;
    this.tx = 0;
    this.ty = 0;
    style.top = '0px';
    style.left = '0px';
  }
  close(e: React.MouseEvent) {
    const { id, router } = this.props;
    e.stopPropagation();
    // this.options?.onClose();
    router.remove(id);
  }
  zoom(event: React.MouseEvent, direction: string) {
    this.getInfo(event);
    let _this = this;
    document.onmousemove = (e: MouseEvent) => {
      switch (direction) {
        case 'left':
          _this.leftInfo(e);
          break;
        case 'right':
          _this.rightInfo(e);
          break;
        case 'top':
          _this.topInfo(e);
          break;
        case 'bottom':
          _this.bottomInfo(e);
          break;
        case 'leftTop':
          _this.leftTopInfo(e);
          break;
        case 'leftBottom':
          _this.leftBottomInfo(e);
          break;
        case 'rightTop':
          _this.rightTopInfo(e);
          break;
        case 'rightBottom':
          _this.rightBottomInfo(e);
          break;
      }
      let style = _this.targetRef.current.style;
      // 这里不能直接使用对this.newWidth隐式类型转换来判断，因为this.newWidth===0时，会使用this.width
      let width = _this.newWidth !== undefined ? _this.newWidth : _this.width;
      let height =
        _this.newHeight !== undefined ? _this.newHeight : _this.height;
      let translateX =
        _this.distanceX !== undefined ? _this.distanceX : _this.tx;
      let translateY =
        _this.distanceY !== undefined ? _this.distanceY : _this.ty;
      style.width = `${width}px`;
      style.height = `${height}px`;
      // this.targetRef.current.style.transform = `translate(${translateX}px, ${translateY}px)`;
      style.left = translateX + 'px';
      style.top = translateY + 'px';
    };
  }
  // 获取缩放时宽高、translate等参数的值
  leftInfo(e: MouseEvent) {
    this.newWidth = this.width - (e.clientX - this.startX);
    this.distanceX = this.tx + (e.clientX - this.startX);
    if (this.options.limit) {
      this.newWidth = Math.max(
        this.options.minWidth || 0,
        Math.min(this.newWidth, this.width + this.tx),
      );
      this.distanceX = Math.max(
        0,
        Math.min(
          this.distanceX,
          this.width + this.tx - (this.options.minWidth || 0),
        ),
      );
    }
  }
  rightInfo(e: MouseEvent) {
    this.newWidth = this.width + (e.clientX - this.startX);
    if (this.options.limit) {
      this.newWidth = Math.max(
        this.options.minWidth || 0,
        Math.min(this.newWidth, this.maxWidth - this.tx),
      );
    }
  }
  topInfo(e: MouseEvent) {
    this.newHeight = this.height - (e.clientY - this.startY);
    this.distanceY = this.ty + (e.clientY - this.startY);
    if (this.options.limit) {
      this.newHeight = Math.max(
        this.options.minHeight || 0,
        Math.min(this.newHeight, this.height + this.ty),
      );
      this.distanceY = Math.max(
        0,
        Math.min(
          this.distanceY,
          this.height + this.ty - (this.options.minHeight || 0),
        ),
      );
    }
  }
  bottomInfo(e: MouseEvent) {
    this.newHeight = this.height + (e.clientY - this.startY);
    if (this.options.limit) {
      this.newHeight = Math.max(
        this.options.minHeight || 0,
        Math.min(this.newHeight, this.maxHeight - this.ty),
      );
    }
  }
  leftTopInfo(e: MouseEvent) {
    this.leftInfo(e);
    this.topInfo(e);
  }
  leftBottomInfo(e: MouseEvent) {
    this.leftInfo(e);
    this.bottomInfo(e);
  }
  rightTopInfo(e: MouseEvent) {
    this.rightInfo(e);
    this.topInfo(e);
  }
  rightBottomInfo(e: MouseEvent) {
    this.rightInfo(e);
    this.bottomInfo(e);
  }
  render() {
    const { children, onClick } = this.props;
    const options = this.options || {};
    return (
      <div
        ref={this.targetRef}
        className="drag-box"
        onMouseDown={this.handleMousedown}
      >
        {options.header && (
          <div className="drag-header" onMouseDown={this.onDrag}>
            <h3>{options.name}</h3>
            <div className="drag-btns">
              <i
                className="drag-btn icon-zoom-out"
                onMouseDown={(e) => this.zoomOut(e)}
              ></i>
              {/* <i className="drag-btn icon-zoom-in" onMouseDown={e => this.zoomIn(e)}></i> */}
              <i
                className="drag-btn icon-close"
                onMouseDown={(e) => this.close(e)}
              ></i>
            </div>
          </div>
        )}

        <div className="drag-content">{children}</div>

        {options.drag && (
          <>
            <div
              className="horn leftTop"
              onMouseDown={(e) => this.zoom(e, 'leftTop')}
            ></div>
            <div
              className="horn rightTop"
              onMouseDown={(e) => this.zoom(e, 'rightTop')}
            ></div>
            <div
              className="horn leftBottom"
              onMouseDown={(e) => this.zoom(e, 'leftBottom')}
            ></div>
            <div
              className="horn rightBottom"
              onMouseDown={(e) => this.zoom(e, 'rightBottom')}
            ></div>
            <div
              className="vertical left"
              onMouseDown={(e) => this.zoom(e, 'left')}
            ></div>
            <div
              className="vertical right"
              onMouseDown={(e) => this.zoom(e, 'right')}
            ></div>
            <div
              className="horizontal top"
              onMouseDown={(e) => this.zoom(e, 'top')}
            ></div>
            <div
              className="horizontal bottom"
              onMouseDown={(e) => this.zoom(e, 'bottom')}
            ></div>

            <div className="mask"></div>
          </>
        )}
      </div>
    );
  }
}
export default function SysPage(RouteOption: GT.IRouterOptions) {
  const { component, options, models } = RouteOption;

  const DynamicComponent = React.lazy(async () => {
    if (models) {
      let model = (await models()).default;
      // 防止models多次注册
      if (!app._models.find((item: any) => item.namespace == model.namespace)) {
        app.model(model);
      }
    }
    return component();
  });

  return (props: any) => {
    const {
      params,
      router,
      id,
      zoomOut,
      options: propsOptions,
      onActive,
    } = props;

    let newOptions = propsOptions || options;

    return (
      <DragComponent
        options={newOptions}
        router={router}
        id={id}
        onActive={onActive}
        zoomOut={zoomOut}
      >
        <React.Suspense fallback={<Loading />}>
          <DynamicComponent params={params} router={router} id={id} />
        </React.Suspense>
      </DragComponent>
    );
  };
}
