<template>
  <el-dialog
    custom-class="background"
    width="608px"
    :close-on-click-modal="false"
    :visible="visible"
    :before-close="handleClose"
  >
    <div class="select-background">
      <div class="select-background-top">
        <span class="tab">背景图</span>
        <SelectUpload type="image" @uploadSuccess="uploadSuccess" />
      </div>
      <div class="background-img">
        <div v-if="file_url" class="img-set" :style="{ top: `${imgData.top - 9}px`, left: `${imgData.left}px` }">
          <div class="dot top-left" @mousedown="dragStart($event, 'nwse-resize', 'top-left')"></div>
          <div class="horizontal-line" @mousedown="dragStart($event, 'ns-resize', 'top')"></div>
          <div class="dot top-right" @mousedown="dragStart($event, 'nesw-resize', 'top-right')"></div>
          <div class="vertical-line" @mousedown="dragStart($event, 'ew-resize', 'left')"></div>
          <img
            :src="file_url"
            draggable="false"
            alt="背景图"
            :style="{ width: `${imgData.width}px`, height: `${imgData.height}px` }"
            @mousedown="dragStart($event, 'move', 'move')"
          />
          <div class="vertical-line" @mousedown="dragStart($event, 'ew-resize', 'right')"></div>
          <div class="dot bottom-left" @mousedown="dragStart($event, 'nesw-resize', 'bottom-left')"></div>
          <div class="horizontal-line" @mousedown="dragStart($event, 'ns-resize', 'bottom')"></div>
          <div class="dot bottom-right" @mousedown="dragStart($event, 'nwse-resize', 'bottom-right')"></div>
        </div>
      </div>
    </div>

    <div slot="footer">
      <el-button @click="handleClose">取消</el-button>
      <el-button type="primary" @click="confirm">确定</el-button>
    </div>
  </el-dialog>
</template>

<script>
import SelectUpload from './common/SelectUpload.vue';

export default {
  name: 'SelectBackground',
  components: {
    SelectUpload,
  },
  props: {
    visible: {
      type: Boolean,
      required: true,
    },
  },
  data() {
    return {
      maxWidth: 576,
      maxHeight: 310,
      file_url: '',
      drag: {
        dragging: false,
        startX: 0,
        startY: 0,
        type: '',
      },
      imgData: {
        width: 0,
        height: 0,
        top: 0,
        left: 0,
      },
    };
  },
  mounted() {
    document.querySelector('.el-dialog__wrapper').addEventListener('mousemove', this.mouseMove);
    document.body.addEventListener('mouseup', this.mouseUp);
  },
  beforeDestroy() {
    document.querySelector('.el-dialog__wrapper')?.removeEventListener('mousemove', this.mouseMove);
    document.body.removeEventListener('mouseup', this.mouseUp);
  },
  methods: {
    handleClose() {
      this.$emit('update:visible', false);
    },
    confirm() {
      this.$emit('update:visible', false);
      const { width, height, top, left } = this.imgData;
      this.$emit('setBackgroundImage', this.file_url, {
        width: (width / this.maxWidth) * 100,
        height: (height / this.maxHeight) * 100,
        top: (top / this.maxHeight) * 100,
        left: (left / this.maxWidth) * 100,
      });
    },
    /**
     * 拖拽开始
     * @param {MouseEvent} event
     * @param {string} cursor
     * @param {string} type
     */
    dragStart(event, cursor, type) {
      const { clientX, clientY } = event;
      this.drag = {
        dragging: true,
        startX: clientX,
        startY: clientY,
        type,
      };

      document.querySelector('.el-dialog__wrapper').style.cursor = cursor;
    },
    /**
     * 鼠标移动
     * @param {MouseEvent} event
     */
    mouseMove(event) {
      if (!this.drag.dragging) return;
      const { clientX, clientY } = event;
      const { startX, startY, type } = this.drag;

      const widthDiff = clientX - startX;
      const heightDiff = clientY - startY;

      if (type === 'top-left') {
        this.imgData.width = Math.min(this.maxWidth, Math.max(0, this.imgData.width - widthDiff));
        this.imgData.height = Math.min(this.maxHeight, Math.max(0, this.imgData.height - heightDiff));
        this.imgData.top = Math.min(this.maxHeight - this.imgData.height, Math.max(0, this.imgData.top + heightDiff));
        this.imgData.left = Math.min(this.maxWidth - this.imgData.width, Math.max(0, this.imgData.left + widthDiff));
      } else if (type === 'top-right') {
        this.imgData.width = Math.min(this.maxWidth, Math.max(this.imgData.width + widthDiff));
        this.imgData.height = Math.min(this.maxHeight, Math.max(0, this.imgData.height - heightDiff));
        this.imgData.top = Math.min(this.maxHeight - this.imgData.height, Math.max(0, this.imgData.top + heightDiff));
        this.imgData.left = Math.min(this.maxWidth - this.imgData.width, Math.max(0, this.imgData.left));
      } else if (type === 'bottom-left') {
        this.imgData.width = Math.min(this.maxWidth, Math.max(0, this.imgData.width - widthDiff));
        this.imgData.height = Math.min(this.maxHeight, Math.max(this.imgData.height + heightDiff));
        this.imgData.top = Math.min(this.maxHeight - this.imgData.height, Math.max(0, this.imgData.top));
        this.imgData.left = Math.min(this.maxWidth - this.imgData.width, Math.max(0, this.imgData.left + widthDiff));
      } else if (type === 'bottom-right') {
        this.imgData.width = Math.min(this.maxWidth, Math.max(this.imgData.width + widthDiff));
        this.imgData.height = Math.min(this.maxHeight, Math.max(this.imgData.height + heightDiff));
        this.imgData.top = Math.min(this.maxHeight - this.imgData.height, Math.max(0, this.imgData.top));
        this.imgData.left = Math.min(this.maxWidth - this.imgData.width, Math.max(0, this.imgData.left));
      }

      if (type === 'top') {
        this.imgData.height = Math.min(this.maxHeight, Math.max(0, this.imgData.height - heightDiff));
        this.imgData.top = Math.min(this.maxHeight - this.imgData.height, Math.max(0, this.imgData.top + heightDiff));
      } else if (type === 'bottom') {
        this.imgData.height = Math.min(this.maxHeight, Math.max(this.imgData.height + heightDiff));
        this.imgData.top = Math.min(this.maxHeight - this.imgData.height, Math.max(0, this.imgData.top));
      } else if (type === 'left') {
        this.imgData.width = Math.min(this.maxWidth, Math.max(this.imgData.width - widthDiff));
        this.imgData.left = Math.min(this.maxWidth - this.imgData.width, Math.max(0, this.imgData.left + widthDiff));
      } else if (type === 'right') {
        this.imgData.width = Math.min(this.maxWidth, Math.max(this.imgData.width + widthDiff));
        this.imgData.left = Math.min(this.maxWidth - this.imgData.width, Math.max(0, this.imgData.left));
      }

      if (type === 'move') {
        this.imgData.top = Math.min(this.maxHeight - this.imgData.height, Math.max(0, this.imgData.top + heightDiff));
        this.imgData.left = Math.min(this.maxWidth - this.imgData.width, Math.max(0, this.imgData.left + widthDiff));
      }
      this.drag.startX = clientX;
      this.drag.startY = clientY;
    },
    /**
     * 鼠标抬起
     */
    mouseUp() {
      this.drag.dragging = false;
      document.querySelector('.el-dialog__wrapper').style.cursor = 'auto';
    },
    /**
     * 上传成功
     * @param {array} fileList
     */
    uploadSuccess(fileList) {
      if (fileList.length > 0) {
        let file_url = fileList[0].file_url;
        const img = new Image();
        img.src = file_url;
        img.onload = () => {
          const { width, height } = img;

          if (width > this.maxWidth || height > this.maxHeight) {
            const wScale = width / this.maxWidth;
            const hScale = height / this.maxHeight;
            const scale = wScale > hScale ? this.maxWidth / 2 / width : this.maxHeight / 2 / height;

            this.imgData = {
              width: width * scale,
              height: height * scale,
              top: 0,
              left: 0,
            };
          } else {
            this.imgData = {
              width,
              height,
              top: 0,
              left: 0,
            };
          }
          this.file_url = fileList[0].file_url_open;
        };
      }
    },
  },
};
</script>

<style lang="scss" scoped>
.select-background {
  &-top {
    display: flex;
    align-items: center;
    margin-bottom: 16px;

    .tab {
      width: 80px;
      font-size: 14px;
      color: $font-light-color;
    }
  }

  .background-img {
    height: 310px;
    border: 1px dashed rgba(0, 0, 0, 8%);

    .img-set {
      position: relative;
      display: inline-grid;
      grid-template:
        ' . . . ' 2px
        ' . img . ' auto
        ' . . . ' 2px
        / 2px auto 2px;

      img {
        object-fit: cover;
      }

      .horizontal-line,
      .vertical-line {
        background-color: $main-color;
      }

      .horizontal-line {
        width: 100%;
        height: 2px;
        cursor: ns-resize;
      }

      .vertical-line {
        width: 2px;
        height: 100%;
        cursor: ew-resize;
      }

      .dot {
        z-index: 1;
        width: 6px;
        height: 6px;
        background-color: $main-color;

        &.top-left {
          top: -2px;
          left: -2px;
        }

        &.top-right {
          top: -2px;
          right: 2px;
        }

        &.bottom-left {
          bottom: 2px;
          left: -2px;
        }

        &.bottom-right {
          right: 2px;
          bottom: 2px;
        }

        &.top-left,
        &.bottom-right {
          position: relative;
          cursor: nwse-resize;
        }

        &.top-right,
        &.bottom-left {
          position: relative;
          cursor: nesw-resize;
        }
      }
    }
  }
}
</style>

<style lang="scss">
.el-dialog.background {
  .el-dialog__header {
    display: none;
  }

  .el-dialog__body {
    padding: 8px 16px;
  }
}
</style>
