<template>
  <div class="gva-cropper-btn">
    <label :class="`btn btn-${props.btnType}`" :for="`uploads_${props.name}`">
      <el-icon>
        <Crop />
      </el-icon>
      <span>裁剪上传</span>
    </label>
    <input type="file" :id="`uploads_${props.name}`" style="display: none;"
      accept="image/png, image/jpeg, image/gif, image/jpg, image/webp" @change="handleSelectImg($event)">
  </div>

  <el-drawer v-model="showDrawer" title="上传头像" direction="ltr" :show-close="false" :close-on-press-escape="false"
    :close-on-click-modal="false" destroy-on-close append-to-body
    :size="Math.max(800, Math.min(1500, props.imgWidth + 140))">
    <template #header>
      <div class="flex justify-between items-center">
        <span class="text-lg">裁剪上传图片</span>
        <div>
          <el-button type="primary" @click="handleConfirm('blob')">确 定</el-button>
          <el-button @click="showDrawer = false">取 消</el-button>
        </div>
      </div>
    </template>

    <div class="gva-cropper-content flex">
      <div class="cropper"
        :style="{ 'width': Math.max(760, Math.min(1500, props.imgWidth + 100)) + 'px', 'min-height': Math.max(Math.min(props.imgHeight + 200, 900), 500) + 'px' }">
        <div class="gva-btn-list">
          <el-button @click="changeScale(1)">
            <el-icon>
              <ZoomIn />
            </el-icon>
          </el-button>
          <el-button @click="changeScale(-1)">
            <el-icon>
              <ZoomOut />
            </el-icon>
          </el-button>
          <el-button @click="rotateLeft">
            <el-icon>
              <RefreshLeft />
            </el-icon>
          </el-button>
          <el-button @click="rotateRight">
            <el-icon>
              <RefreshRight />
            </el-icon>
          </el-button>
        </div>
        <vue-cropper v-if="showDrawer" ref="vueCropperRef" :outputSize="1" outputType="png" :img="vueCropperImg"
          :info="true" :full="true" autoCrop :centerBox="props.cropType === 'fixed' ? true : false"
          :autoCropWidth="props.imgWidth" :autoCropHeight="props.imgHeight"
          :fixedBox="props.cropType === 'fixed' ? true : false" :fixedNumber="props.fixedNumber" :maxImgSize="2000" />
      </div>
    </div>
  </el-drawer>
</template>

<script setup>
import { ref } from 'vue'
import VueCropper from "@/components/vueCropper";
import { ElMessage } from 'element-plus'
import axios from 'axios'

defineOptions({
  name: 'CropperImg',
})

const showDrawer = ref(false)
const vueCropperImg = ref(null)
const vueCropperRef = ref(null)

const props = defineProps({
  imgWidth: {
    required: true,
    type: Number
  },
  imgHeight: {
    required: true,
    type: Number
  },
  category: {
    required: true,
    type: String
  },
  name: {
    type: String,
    default: 'media'
  },
  cropType: {
    type: String,
    default: 'fixed'
  },
  outputSize: {
    type: Number,
    default: 1
  },
  fixed: {
    type: Boolean,
    default: true
  },
  fixedNumber: {
    type: Array,
    default: function () {
      return [1, 1]
    }
  },
  btnType: {
    type: String,
    default: 'default'
  },
})

const emits = defineEmits(['on-success', 'update:modelValue'])

const changeScale = (num) => {
  num = num || 1
  vueCropperRef.value.changeScale(num)
}
const rotateLeft = () => {
  vueCropperRef.value.rotateLeft()
}
const rotateRight = () => {
  vueCropperRef.value.rotateRight()
}
// 实时预览函数 
// const realTime = (data) => {
//   previews.value = data
// }
const handleConfirm = (type) => {
  // 输出 
  if (type === 'blob') {
    vueCropperRef.value.getCropBlob(async (data) => {
      doConfirm(data)
    })
  } else {
    vueCropperRef.getCropData(async (data) => {
      doConfirm(data)
    })
  }
}
// 判断是哪种缩放方式
const doConfirm = (cropData) => {
  const originalBlob = cropData // 原始 Blob 对象
  const desiredWidth = props.imgWidth// 所需的宽度
  const desiredHeight = props.imgHeight // 所需的高度
  if (props.cropType == 'fixed') {
    // 如果是需要固定宽高的图片，直接调用方法缩放图片
    handleResizeBlob(originalBlob, desiredWidth, desiredHeight)
  } else if (props.cropType == 'max') {
    // 如果是需要不超过xxx宽高的图片，先做判断
    var blob = new Blob([cropData], { type: 'image/png' })
    var img = new Image()
    var url = window.URL.createObjectURL(blob)
    img.src = url
    img.onload = function () {
      // 获取图像的宽度和高度
      var width = img.width
      var height = img.height

      if (width <= desiredWidth && height <= desiredHeight) {
        // 如果裁剪完未超过限制，则直接去上传
        uploadImage(cropData)
      } else {
        // 如果裁剪完超过限制，则调用方法缩放图片
        handleResizeBlob(originalBlob, desiredWidth, desiredHeight)
      }
      // 清理 URL 对象
      window.URL.revokeObjectURL(url)
    }
  }
}

// 缩放图片
const resizeBlob = (blob, desiredWidth, desiredHeight) => {
  return new Promise((resolve, reject) => {
    const img = new Image()
    img.onload = () => {
      const canvas = document.createElement('canvas')
      const ctx = canvas.getContext('2d')

      // 计算缩放比例
      const scaleX = desiredWidth / img.width
      const scaleY = desiredHeight / img.height
      const scale = Math.min(scaleX, scaleY)

      // 设置 Canvas 的宽度和高度
      canvas.width = desiredWidth
      canvas.height = desiredHeight

      // 绘制图片到 Canvas 上，并进行缩放
      ctx.drawImage(img, 0, 0, img.width * scale, img.height * scale)

      // 将 Canvas 中的图像转换为 Blob 对象
      canvas.toBlob((resizedBlob) => {
        resolve(resizedBlob)
      }, blob.type)
    }

    img.onerror = (error) => {
      reject(error)
    }

    img.src = window.URL.createObjectURL(blob)
  })
}
// 缩放后上传
const handleResizeBlob = (originalBlob, desiredWidth, desiredHeight) => {
  resizeBlob(originalBlob, desiredWidth, desiredHeight)
    .then((resizedBlob) => {
      uploadImage(resizedBlob)
    })
    .catch((error) => {
      console.error('Error resizing Blob:', error)
    })
}

const uploadImage = (data) => {
  const formData = new FormData();
  formData.append('file', data, props.name + '_image.png'); // 假设使用'image.jpg'作为上传的文件名
  const path = import.meta.env.VITE_BASE_API + '/cms/mediaFile/upload?category=' + props.category
  axios.post(path, formData, {
    headers: {
      'Content-Type': 'multipart/form-data'
    }
  })
    .then(res => {
      // 处理上传成功的响应
      if (res.data.code === 0) {
        emits('on-success', res.data)
        emits('update:modelValue', res.data.data.url)
        showDrawer.value = false
      } else {
        ElMessage({
          type: 'error',
          message: '上传失败'
        })
      }
    })
    .catch(error => {
      // 处理上传失败的错误
      console.error('上传失败', error);
      ElMessage({
        type: 'error',
        message: '上传失败'
      })
    })
}

const handleSelectImg = (e) => {
  var file = e.target.files[0]
  if (! /\.(gif|jpg|jpeg|png|bmp|webp|GIF|JPG|PNG)$/.test(e.target.value)) {
    ElMessage({
      type: 'error',
      message: '图片类型必须是.gif,jpeg,jpg,png,bmp中的一种'
    })
    return false
  }
  var reader = new FileReader()
  reader.onloadend = (e) => {
    let data
    if (typeof e.target.result === 'object') {
      // 把Array Buffer转化为blob 如果是base64不需要 
      data = window.URL.createObjectURL(new Blob([e.target.result]))
    } else {
      data = e.target.result
    }
    vueCropperImg.value = data
    showDrawer.value = true

  }
  reader.readAsArrayBuffer(file)
  e.target.value = ''
}

// 初始化方法
const open = async (data) => {
  showDrawer.value = true
  vueCropperImg.value = data
}

// 对外暴露方法
defineExpose({ open })
</script>

<style lang="scss">
.gva-cropper-content {
  justify-content: flex-start;
  -webkit-justify-content: flex-start;

  .cropper {
    width: 565px;
    height: 600px;

    .gva-btn-list {
      justify-content: center;
      -webkit-justify-content: center;
    }
  }

  .show-preview {
    margin-right: 15px;

    .preview-title {
      line-height: 42px;
    }

    .preview {
      box-sizing: border-box;
      overflow: hidden;
      /*border-radius: 50%;*/
      border: 2px solid var(--el-border-color-dark);
      background: #cccccc;
      margin-right: 20px;
    }
  }
}

.gva-cropper-btn {
  display: inline-flex;

  .btn {
    min-width: 108px;
    display: inline-flex;
    box-sizing: border-box;
    line-height: 1;
    height: 32px;
    padding: 8px 15px;
    border-radius: var(--el-border-radius-base);
    cursor: pointer;
    position: relative;
    overflow: hidden;
    transition: var(--el-transition-duration-fast);
    vertical-align: middle;
    justify-content: center;
    align-items: center;
    outline: none;

    >span {
      margin-left: 6px;
    }
  }

  .btn-default {
    border: 1px solid var(--el-border-color);
    color: var(--el-text-color-regular);
    background-color: var(--el-fill-color-blank);
  }

  .btn-default:hover {
    border-color: var(--el-color-primary);
    color: var(--el-color-primary);
  }

  .btn-primary {
    border: 1px solid var(--el-color-primary-light-5);
    color: var(--el-color-primary);
    background-color: var(--el-color-primary-light-9);
  }

  .btn-primary:hover {
    border: 1px solid var(--el-color-primary);
    color: var(--el-color-white);
    background-color: var(--el-color-primary);
  }
}
</style>
