<template>
  <div class="border border-solid border-gray-100 h-full">
    <Toolbar
      :editor="editorRef"
      :default-config="toolbarConfig"
      mode="default"
    />
    <Editor
      v-model="valueHtml"
      class="overflow-y-hidden mt-0.5"
      style="min-height: 18rem"
      :default-config="editorConfig"
      mode="default"
      @onCreated="handleCreated"
      @onChange="change"
    />
  </div>
</template>

<script setup>
  import '@wangeditor/editor/dist/css/style.css' // 引入 css

  const basePath = import.meta.env.VITE_BASE_API

  import { onBeforeUnmount, ref, shallowRef, watch } from 'vue'
  import { Editor, Toolbar } from '@wangeditor/editor-for-vue'

  import { ElMessage } from 'element-plus'
  import { getUrl } from '@/utils/image'
  import botLogo from '@/assets/bot_logo.png'

  const emits = defineEmits(['change', 'update:modelValue'])

  const change = (editor) => {
    emits('change', editor)
    emits('update:modelValue', valueHtml.value)
  }

  const props = defineProps({
    modelValue: {
      type: String,
      default: ''
    },
    useWatermark: {
      type: Boolean,
      default: false
    }
  })

  const editorRef = shallowRef()
  const valueHtml = ref('')

  const toolbarConfig = {}
  const editorConfig = {
    placeholder: '请输入内容...',
    MENU_CONF: {
      uploadImage: {
        server: basePath + '/fileUploadAndDownload/upload?noSave=1',
        fieldName: 'file',
        maxFileSize: 1024 * 1024 * 10, // 限制图片大小为10MB
        maxNumberOfFiles: 1,
        async customUpload(file, insertFn) {
          // 未开启水印则直接上传原图
          if (!props.useWatermark) {
            const formData = new FormData()
            formData.append('file', file)
            const resp = await fetch(basePath + '/fileUploadAndDownload/upload?noSave=1', { method: 'POST', body: formData })
            const res = await resp.json()
            if (res.code === 0) {
              const urlPath = getUrl(res.data.file.url)
              insertFn(urlPath, res.data.file.name)
            } else {
              ElMessage.error(res.msg || '上传失败')
            }
            return
          }
          try {
            const watermarkedBlob = await addBottomWatermark(file, {
              stripRatio: 0.18, // 水印条高度占原图高度比例
              background: 'rgba(255,255,255,0.96)',
              text: '老陈机器人',
              textColor: '#333',
              fontFamily: 'PingFang SC, Microsoft YaHei, Arial',
              logo: botLogo
            })

            const newFile = new File([watermarkedBlob], file.name, { type: watermarkedBlob.type || file.type })
            const formData = new FormData()
            formData.append('file', newFile)
            const resp = await fetch(basePath + '/fileUploadAndDownload/upload?noSave=1', {
              method: 'POST',
              body: formData
            })
            const res = await resp.json()
            if (res.code === 0) {
              const urlPath = getUrl(res.data.file.url)
              insertFn(urlPath, res.data.file.name)
            } else {
              ElMessage.error(res.msg || '上传失败')
            }
          } catch {
            ElMessage.error('处理水印失败')
            // 降级：直接走原图上传
            const formData = new FormData()
            formData.append('file', file)
            const resp = await fetch(basePath + '/fileUploadAndDownload/upload?noSave=1', { method: 'POST', body: formData })
            const res = await resp.json()
            if (res.code === 0) {
              const urlPath = getUrl(res.data.file.url)
              insertFn(urlPath, res.data.file.name)
            } else {
              ElMessage.error(res.msg || '上传失败')
            }
          }
        },
        customInsert(res, insertFn) {
          if (res.code === 0) {
            const urlPath = getUrl(res.data.file.url)
            insertFn(urlPath, res.data.file.name)
            return
          }
          ElMessage.error(res.msg)
        }
      },
      uploadVideo: {
        server: basePath + '/fileUploadAndDownload/upload?noSave=1',
        fieldName: 'file',
        maxFileSize: 1024 * 1024 * 100, // 限制视频大小为100MB
        maxNumberOfFiles: 1,
        customInsert(res, insertFn) {
          if (res.code === 0) {
            const urlPath = getUrl(res.data.file.url)
            insertFn(urlPath, res.data.file.name)
            return
          }
          ElMessage.error(res.msg)
        }
      }
    }
  }
  editorConfig.MENU_CONF['uploadImage','uploadVideo'] = {
    fieldName: 'file',
    server: basePath + '/fileUploadAndDownload/upload?noSave=1',
    customInsert(res, insertFn) {
      if (res.code === 0) {
        const urlPath = getUrl(res.data.file.url)
        insertFn(urlPath, res.data.file.name)
        return
      }
      ElMessage.error(res.msg)
    }
  }

  // 组件销毁时，也及时销毁编辑器
  onBeforeUnmount(() => {
    const editor = editorRef.value
    if (editor == null) return
    editor.destroy()
  })

  const handleCreated = (editor) => {
    editorRef.value = editor
    valueHtml.value = props.modelValue
  }

  watch(
    () => props.modelValue,
    () => {
      valueHtml.value = props.modelValue
    }
  )

  async function addBottomWatermark(file, options) {
    const { stripRatio = 0.18, background = 'rgba(255,255,255,0.96)', text = '', textColor = '#333', fontFamily = 'Arial', logo } = options || {}

    const img = await fileToImage(file)
    const width = img.naturalWidth || img.width
    const height = img.naturalHeight || img.height
    const stripHeight = Math.max(60, Math.floor(height * stripRatio))

    const canvas = document.createElement('canvas')
    canvas.width = width
    canvas.height = height + stripHeight
    const ctx = canvas.getContext('2d')

    // 原图
    ctx.drawImage(img, 0, 0, width, height)

    // 底部水印条背景
    ctx.fillStyle = background
    ctx.fillRect(0, height, width, stripHeight)

    // 左侧 Logo（可选）
    let logoSize = Math.floor(stripHeight * 0.6)
    let logoPadding = Math.floor(stripHeight * 0.2)
    if (logo) {
      try {
        const logoImg = await srcToImage(logo)
        const ratio = logoImg.width / logoImg.height
        const drawW = logoSize
        const drawH = Math.floor(drawW / ratio)
        const y = height + Math.floor((stripHeight - drawH) / 2)
        ctx.drawImage(logoImg, logoPadding, y, drawW, drawH)
      } catch { void 0 }
    }

    // 右侧文字
    ctx.fillStyle = textColor
    const fontSize = Math.floor(stripHeight * 0.38)
    ctx.font = `${fontSize}px ${fontFamily}`
    ctx.textBaseline = 'middle'
    ctx.textAlign = 'right'
    const textPadding = Math.floor(stripHeight * 0.25)
    ctx.fillText(text, width - textPadding, height + Math.floor(stripHeight / 2))

    const blob = await canvasToBlob(canvas, file.type || 'image/png')
    return blob
  }

  function fileToImage(file) {
    return new Promise((resolve, reject) => {
      const reader = new FileReader()
      reader.onload = () => {
        const img = new Image()
        img.onload = () => resolve(img)
        img.onerror = reject
        img.src = reader.result
      }
      reader.onerror = reject
      reader.readAsDataURL(file)
    })
  }

  function srcToImage(src) {
    return new Promise((resolve, reject) => {
      const img = new Image()
      img.crossOrigin = 'anonymous'
      img.onload = () => resolve(img)
      img.onerror = reject
      img.src = src
    })
  }

  function canvasToBlob(canvas, mime) {
    return new Promise((resolve) => {
      if (canvas.toBlob) {
        canvas.toBlob((blob) => resolve(blob), mime, 0.92)
      } else {
        // 兼容处理
        const dataURL = canvas.toDataURL(mime)
        const arr = dataURL.split(',')
        const bstr = atob(arr[1])
        let n = bstr.length
        const u8arr = new Uint8Array(n)
        while (n--) u8arr[n] = bstr.charCodeAt(n)
        resolve(new Blob([u8arr], { type: mime }))
      }
    })
  }
</script>

<style scoped lang="scss"></style>
