import PropTypes from "prop-types";
import React from "react";
import $calc from "../../utils/common";
import "./index.module.scss";
import { Button, Dialog, } from "zent";
// 按需引入
// import Button from 'zent/lib/button';
// import Dialog from 'zent/lib/dialog';

export default class CalcPopUpDialog extends React.Component {
  //#region 属性 & 构造函数

  static propTypes = {
    lv: PropTypes.number,
    customClass: PropTypes.string,

    // 弹框标题
    title: PropTypes.string,
    // 是否显示弹框
    isShow: PropTypes.bool.isRequired,
    // 是否显示右上角关闭按钮
    isShowClose: PropTypes.bool,
    // 是否显示确认按钮
    isShowConfirm: PropTypes.bool,
    // 是否显示确认按钮的loading
    isShowConfirmLoading: PropTypes.bool,
    // 是否显示取消按钮
    isShowCancel: PropTypes.bool,
    // 是否显示遮罩层
    isShowMask: PropTypes.bool,
    // 确认按钮文本
    cofirmText: PropTypes.string,
    // 取消按钮文本
    cancelText: PropTypes.string,
    // 弹框底部水平轴对齐方式
    footerJustifyContent: PropTypes.string,
    // 弹框宽度
    width: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.number,
    ]),
    // 弹框高度
    height: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.number,
    ]),
    // 弹框最大高度
    maxHeight: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.number,
    ]),
    // 弹框外边距
    contentMargin: PropTypes.string,
    // 弹框是否可拖拽
    canDrag: PropTypes.bool,
    // children: PropTypes.element.isRequired,

    updateIsShow: PropTypes.func,
    onClose: PropTypes.func,
    onOpen: PropTypes.func,
    onConfirm: PropTypes.func,
    onCencel: PropTypes.func,
    onMove: PropTypes.func,
  };
  static defaultProps = {
    lv: 7,
    customClass: "custom-calc-pop-up-dialog",
    title: "",
    isShow: false,
    isShowClose: true,
    isShowConfirm: true,
    isShowConfirmLoading: false,
    isShowCancel: true,
    isShowMask: true,
    cofirmText: "Confirm",
    cancelText: "Cancel",
    footerJustifyContent: "flex-end",
    width: 720,
    height: 400,
    maxHeight: "",
    contentMargin: "0px",
    canDrag: true,

    updateIsShow: (isShow) => {
      console.log(`updateIsShow`, isShow);
    },
    onClose: () => {
      console.log(`onClose`);
    },
    onOpen: () => {
      console.log(`onOpen`);
    },
    onConfirm: () => {
      console.log(`onConfirm`);
    },
    onCencel: () => {
      console.log(`onCencel`);
    },
    onMove: () => {
      console.log(`onMove`);
    },
  };

  constructor(props) {
    super(props);
    this.state = {};
  }

  data = {
    // 分配一个唯一id, 保证组件间的拖拽互不影响
    dialogId: `dialogId_${$calc.tool.createMD5($calc.tool.generateGUID())}`,
  };

  dialogRef = React.createRef();

  //#endregion

  //#region hooks

  render() {
    const _self = this;
    const {
      lv,
      customClass,
      title,
      isShow,
      isShowClose,
      isShowConfirm,
      isShowConfirmLoading,
      isShowCancel,
      isShowMask,
      cofirmText,
      cancelText,
      footerJustifyContent,
      width,
      height,
      maxHeight,
      contentMargin,
      margin,
      canDrag,
      children,
      updateIsShow,
      onClose,
      onOpen,
      onConfirm,
      onCencel,
      onMove,
    } = _self.props;
    const slotObj = $calc.tool.getNamedSlots(children);
    return (
      <Dialog
        ref={_self.dialogRef}
        title={title}
        visible={isShow}
        closeBtn={isShowClose}
        mask={isShowMask}
        maskClosable={false}
        style={_self.getStyleObj()}
        className={`${customClass} ${_self.data.dialogId} calc-pop-up-dialog`}
        onClose={() => {
          _self.onCloseEvent && _self.onCloseEvent();
        }}
      >
        <div className="dialog-body-wrap">
          <div className="dialog-content-wrap">{slotObj.default}</div>
        </div>

        {slotObj.footer
          ? slotObj.footer
          : (isShowCancel || isShowConfirm) && (
              <div className="dialog-footer-wrap">
                {isShowCancel && (
                  <div
                    className="btn btn-cancel"
                    onClick={() => {
                      _self.onCencelEvent();
                    }}
                  >
                    {cancelText}
                  </div>
                )}
                {isShowConfirm && (
                  <Button
                    type="primary"
                    className="btn btn-confirm"
                    loading={isShowConfirmLoading}
                    onClick={() => {
                      _self.onConfirmEvent();
                    }}
                  >
                    {isShowConfirmLoading ? "" : cofirmText}
                  </Button>
                )}
              </div>
            )}
      </Dialog>
    );
  }

  componentDidMount() {
    // const _self = this;
    // console.log(
    //   `calc-pop-up-dialog componentWillUnmount...`,
    //   _self.dialogRef.current
    // );
  }
  shouldComponentUpdate(nextProps, nextState) {
    const _self = this;
    // 若子组件无属性变化及状态更新, 则无需更新组件
    // Immutable验证的效果不好, 用回JSON.stringify来处理, 排除掉循环引用的属性, 如插槽
    const removeProps = ["children"];
    const nextPropsClone = $calc.tool.deepClone(nextProps, removeProps);
    const curPropsClone = $calc.tool.deepClone(_self.props, removeProps);

    const nextStateClone = $calc.tool.deepClone(nextState, removeProps);
    const curnextStateClone = $calc.tool.deepClone(_self.state, removeProps);

    const needRender =
      JSON.stringify(nextPropsClone) != JSON.stringify(curPropsClone) ||
      JSON.stringify(nextStateClone) != JSON.stringify(curnextStateClone);
    // console.log("calc-pop-up-dialog shouldComponentUpdate...", needRender);
    if (needRender) {
      const { width, height, maxHeight } = _self.props;
      const {
        width: nextWidth,
        height: nextHeight,
        maxHeight: nextMaxHeight,
      } = nextProps;
      if (
        width != nextWidth ||
        height != nextHeight ||
        maxHeight != nextMaxHeight
      ) {
        // 2>计算弹框body高度, 并设置content样式
        _self.calcDialogBodyHeightAndSetContentStyle();
      }

      return true;
    }

    return false;
    // return true;
  }
  componentDidUpdate(prevProps, prevState) {
    const _self = this;
    // 显示弹框, 重置弹框位置
    if (prevProps.isShow != _self.props.isShow && _self.props.isShow == true) {
      _self.openEvent();
    }
  }
  componentWillUnmount() {
    console.log(`calc-pop-up-dialog componentWillUnmount...`);
  }

  //#endregion

  //#region methods

  // 获取样式对象
  getStyleObj() {
    const _self = this;
    let styleObj = {};

    const { width, height, maxHeight } = _self.props;

    // 设置padding
    styleObj["padding"] = "0px";

    // 设置width
    if (!$calc.tool.isNullOrEmpty(width)) {
      styleObj["width"] = $calc.tool.isNum(width) ? `${width}px` : width;
    }

    // 优先使用height
    if (!$calc.tool.isNullOrEmpty(height)) {
      styleObj["height"] = $calc.tool.isNum(height) ? `${height}px` : height;
    } else if (!$calc.tool.isNullOrEmpty(maxHeight)) {
      styleObj["max-height"] = $calc.tool.isNum(maxHeight)
        ? `${maxHeight}px`
        : maxHeight;
    }
    // console.log(`styleObj`, styleObj);

    return styleObj;
  }

  // 弹框打开事件
  // 因为zent弹框的隐藏弹框的实质是销毁弹框, 因此可以在此做一些弹框的初始化动作, 且不需要设置标志位来判断是否首次执行
  openEvent() {
    const _self = this;
    const { canDrag } = _self.props;

    // 1>绑定拖动功能
    canDrag && _self.bindDragFunc();

    // 2>计算弹框body高度, 并设置content样式
    _self.calcDialogBodyHeightAndSetContentStyle();

    // 3>执行显示弹框的后置动作
    _self.props.onOpen && _self.props.onOpen();
  }

  debounceMove = $calc.tool._.debounce(this.moveEvent, 2);
  moveEvent() {
    const _self = this;
    _self.props.onMove && _self.props.onMove();
  }
  callMoveEvent() {
    const _self = this;
    _self.debounceMove && _self.debounceMove();
  }

  // 计算弹框body高度, 并设置content样式
  calcDialogBodyHeightAndSetContentStyle() {
    const _self = this;
    const { contentMargin } = _self.props;
    const { dialogId = "" } = _self.data || {};
    // console.log(
    //   `calcDialogBodyHeightAndSetContentStyle - dialogId`,
    //   _self.data.dialogId
    // );
    if ($calc.tool.isNullOrEmpty(dialogId)) {
      console.error(`dialogId is null!`);
      return false;
    }

    setTimeout(() => {
      // 弹框DOM
      const dialogDOM = document.querySelector(`.${dialogId}`);
      // console.log(`calcDialogBodyHeightAndSetContentStyle`);
      if (!dialogDOM) {
        console.error(`dialogDOM (${dialogId}) is null!`);
        return false;
      }
      const dialogHeight = dialogDOM.clientHeight || 0;

      // 获取头部DOM
      const headerDOM = document.querySelector(
        `.${dialogId} .zent-dialog-r-header`
      );
      // 获取底部DOM
      const foorerDOM = document.querySelector(
        `.${dialogId} .dialog-footer-wrap`
      );

      // 获取弹框body DOM
      const bodyDOM = document.querySelector(`.${dialogId} .dialog-body-wrap`);
      if (!bodyDOM) {
        console.error(`bodyDOM is null!`);
        return false;
      }

      // 获取弹框content DOM
      const contentDOM = document.querySelector(
        `.${dialogId} .dialog-content-wrap`
      );
      if (!contentDOM) {
        console.error(`contentDOM is null!`);
        return false;
      }

      // 1>设置content margin
      contentDOM.style.margin = contentMargin;

      // 2>计算content高度
      let headerHeight = 0;
      if (headerDOM) {
        headerHeight = headerDOM.clientHeight || 0;
      }
      // console.log(`headerHeight:${headerHeight}`);
      let footerHeight = 0;
      if (foorerDOM) {
        footerHeight = foorerDOM.clientHeight || 0;
      }
      // console.log(`footerHeight:${footerHeight}`);

      const contentHeight = dialogHeight - headerHeight - footerHeight;
      // console.log(`contentHeight:${contentHeight}`);
      bodyDOM.style.height = `${contentHeight}px`;
    }, 0);
  }

  // 获取属性对象
  getStyle = (() => {
    if (document.currentStyle) {
      return (dom, attr) => dom.currentStyle[attr];
    } else {
      return (dom, attr) => getComputedStyle(dom, false)[attr];
    }
  })();

  // 绑定拖动功能
  bindDragFunc() {
    const _self = this;
    const { dialogId = "" } = _self.data || {};
    // console.log(`dialogId`, _self.data.dialogId);
    if ($calc.tool.isNullOrEmpty(dialogId)) {
      console.error(`dialogId is null!`);
      return false;
    }

    setTimeout(() => {
      const dialogHeaderEl = document.querySelector(
        `.${dialogId} .zent-dialog-r-header`
      );
      const dragDom = document.querySelector(`.${dialogId}`);
      dialogHeaderEl.style.cursor = "move";
      dragDom.style.top = "0px";

      dialogHeaderEl.onmousedown = (e) => {
        // 鼠标按下，计算当前元素距离可视区的距离
        const disX = e.clientX - dialogHeaderEl.offsetLeft;
        const disY = e.clientY - dialogHeaderEl.offsetTop;

        const dragDomWidth = dragDom.offsetWidth;
        const dragDomHeight = dragDom.offsetHeight;

        const screenWidth = document.body.clientWidth;
        const screenHeight = document.body.clientHeight;

        const minDragDomLeft = dragDom.offsetLeft;
        const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth;

        const minDragDomTop = dragDom.offsetTop;
        const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomHeight;

        // 获取到的值带px 正则匹配替换
        let styL = _self.getStyle(dragDom, "left");
        let styT = _self.getStyle(dragDom, "top");

        if (styL.includes("%")) {
          styL = +document.body.clientWidth * (+styL.replace(/\%/g, "") / 100);
          styT = +document.body.clientHeight * (+styT.replace(/\%/g, "") / 100);
        } else {
          styL = +styL.replace(/\px/g, "");
          styT = +styT.replace(/\px/g, "");
        }

        document.onmousemove = (e) => {
          // 通过事件委托，计算移动的距离
          let left = e.clientX - disX;
          let top = e.clientY - disY;

          // 边界处理
          if (-left > minDragDomLeft) {
            left = -minDragDomLeft;
          } else if (left > maxDragDomLeft) {
            left = maxDragDomLeft;
          }

          if (-top > minDragDomTop) {
            top = -minDragDomTop;
          } else if (top > maxDragDomTop) {
            top = maxDragDomTop;
          }

          // 移动当前元素
          dragDom.style.left = `${left + styL}px`;
          dragDom.style.top = `${top + styT}px`;

          // 触发弹框移动事件
          _self.callMoveEvent && _self.callMoveEvent();
        };

        document.onmouseup = (e) => {
          document.onmousemove = null;
          document.onmouseup = null;
        };
      };
    }, 0);
  }

  // 弹框关闭事件
  onCloseEvent() {
    // console.log(`onCloseEvent`);
    const _self = this;
    const { onClose } = _self.props;
    onClose && onClose();
    _self.toggleDialog(false);
  }
  // 显示/隐藏弹框
  toggleDialog(isShow = true) {
    const _self = this;
    const { updateIsShow } = _self.props;
    updateIsShow && updateIsShow(isShow);
  }
  // 取消按钮点击事件
  onCencelEvent() {
    const _self = this;
    const { onCencel } = _self.props;
    onCencel && onCencel();
    _self.onCloseEvent();
  }
  // 确认按钮点击事件
  onConfirmEvent() {
    const _self = this;
    _self.props.onConfirm && _self.props.onConfirm();
  }

  //#endregion
}
