<script setup>
import { onBeforeUnmount, onMounted, ref, watch } from 'vue'
import 'tui-color-picker/dist/tui-color-picker.css'
import 'tui-image-editor/dist/tui-image-editor.css'

const props = defineProps({
  imageUrl: { type: String, required: true },
  imageName: { type: String, default: 'image' }
})

const emit = defineEmits(['error'])

const editorHost = ref(null)
const isLoading = ref(false)
const isReady = ref(false)

const editorMenus = ['crop', 'flip', 'rotate', 'draw', 'shape', 'icon', 'text', 'filter']
const editorTheme = {
  'common.bi.image': 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==',
  'common.backgroundColor': '#08111f',
  'common.border': '0px',
  'menu.normalLabel.color': '#9fb0c8',
  'menu.activeLabel.color': '#f8fafc',
  'submenu.backgroundColor': 'rgba(8, 17, 31, 0.95)',
  'submenu.partition.color': 'rgba(159, 176, 200, 0.2)',
  'submenu.normalLabel.color': '#9fb0c8',
  'submenu.activeLabel.color': '#f8fafc',
  'checkbox.backgroundColor': '#f8fafc',
  'range.pointer.color': '#f8fafc',
  'range.bar.color': 'rgba(159, 176, 200, 0.3)',
  'range.subbar.color': '#38bdf8',
  'range.value.color': '#f8fafc',
  'range.value.backgroundColor': 'rgba(15, 23, 42, 0.88)',
  'range.value.border': '1px solid rgba(159, 176, 200, 0.22)',
  'range.title.color': '#cbd5e1',
  'colorpicker.button.border': '1px solid rgba(159, 176, 200, 0.2)',
  'colorpicker.title.color': '#e2e8f0'
}

let editorInstance = null
let loadRequestId = 0

function getErrorMessage(error, fallback) {
  return error instanceof Error && error.message ? error.message : fallback
}

function dataUrlToBlob(dataUrl) {
  const [header, body = ''] = String(dataUrl || '').split(',')
  const mimeMatch = header.match(/data:([^;]+);base64/)
  const mimeType = mimeMatch ? mimeMatch[1] : 'image/png'
  const binary = atob(body)
  const bytes = new Uint8Array(binary.length)

  for (let index = 0; index < binary.length; index += 1) {
    bytes[index] = binary.charCodeAt(index)
  }

  return new Blob([bytes], { type: mimeType })
}

async function getImageEditorConstructor() {
  const module = await import('tui-image-editor')
  return module.default || module
}

async function initializeEditor() {
  if (!editorHost.value || !props.imageUrl || editorInstance) return

  isLoading.value = true

  try {
    const ImageEditor = await getImageEditorConstructor()
    editorInstance = new ImageEditor(editorHost.value, {
      includeUI: {
        loadImage: {
          path: props.imageUrl,
          name: props.imageName || 'image'
        },
        menu: editorMenus,
        initMenu: 'draw',
        menuBarPosition: 'bottom',
        uiSize: {
          width: '100%',
          height: '100%'
        },
        theme: editorTheme,
        usageStatistics: false
      },
      cssMaxWidth: 1280,
      cssMaxHeight: 960,
      selectionStyle: {
        cornerSize: 16,
        rotatingPointOffset: 56
      },
      usageStatistics: false
    })

    isReady.value = true
  } catch (error) {
    emit('error', getErrorMessage(error, '图片编辑器加载失败'))
  } finally {
    isLoading.value = false
  }
}

async function reloadImageFromProps() {
  if (!editorInstance || !props.imageUrl) return

  const currentRequestId = ++loadRequestId
  isLoading.value = true

  try {
    await editorInstance.loadImageFromURL(props.imageUrl, props.imageName || 'image')
    editorInstance.clearUndoStack()
    editorInstance.clearRedoStack()
  } catch (error) {
    if (currentRequestId === loadRequestId) {
      emit('error', getErrorMessage(error, '重新载入图片失败'))
    }
  } finally {
    if (currentRequestId === loadRequestId) {
      isLoading.value = false
    }
  }
}

async function exportImageBlob(options = {}) {
  if (!editorInstance) {
    throw new Error('图片编辑器尚未就绪')
  }

  editorInstance.discardSelection()
  const dataUrl = editorInstance.toDataURL({
    format: options.format || 'png',
    quality: typeof options.quality === 'number' ? options.quality : 0.92
  })

  return dataUrlToBlob(dataUrl)
}

function destroyEditor() {
  loadRequestId += 1
  isReady.value = false

  if (!editorInstance) return

  editorInstance.destroy()
  editorInstance = null
}

watch(
  () => props.imageUrl,
  (nextUrl, previousUrl) => {
    if (!editorInstance || !nextUrl || nextUrl === previousUrl) return
    reloadImageFromProps()
  }
)

onMounted(() => {
  initializeEditor()
})

onBeforeUnmount(() => {
  destroyEditor()
})

defineExpose({
  exportImageBlob,
  reloadImageFromProps,
  isReady
})
</script>

<template>
  <div class="image-editor-shell">
    <div v-if="isLoading && !isReady" class="editor-placeholder">
      <div class="editor-placeholder-card">
        <strong>正在装载图片编辑器</strong>
        <p>首次打开会初始化 TUI Image Editor，时间会略长一些。</p>
      </div>
    </div>

    <div
      ref="editorHost"
      class="image-editor-host tui-image-editor-container bottom"
      :class="{ 'is-initializing': isLoading && !isReady }"
    ></div>
  </div>
</template>

<style scoped>
.image-editor-shell {
  position: relative;
  overflow: hidden;
  min-height: 640px;
  height: min(78vh, 920px);
  height: min(78dvh, 920px);
  border: 1px solid var(--github-border);
  border-radius: 18px;
  background:
    radial-gradient(circle at top, rgba(56, 189, 248, 0.14), transparent 32%),
    linear-gradient(180deg, #08111f, #0f172a 58%, #121a2c);
  box-shadow: 0 28px 60px rgba(15, 23, 42, 0.22);
}

.image-editor-host.tui-image-editor-container {
  height: 100%;
  min-height: 100%;
  width: 100%;
}

.image-editor-host.is-initializing {
  visibility: hidden;
}

.editor-placeholder {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}

.editor-placeholder-card {
  width: min(420px, 100%);
  padding: 22px 24px;
  border: 1px solid rgba(159, 176, 200, 0.18);
  border-radius: 18px;
  background: rgba(8, 17, 31, 0.82);
  color: #f8fafc;
  text-align: center;
  backdrop-filter: blur(14px);
}

.editor-placeholder-card strong {
  display: block;
  font-size: 1rem;
}

.editor-placeholder-card p {
  margin: 10px 0 0;
  color: rgba(226, 232, 240, 0.84);
  line-height: 1.7;
}

.image-editor-shell :deep(.tui-image-editor-container) {
  background: transparent;
}

.image-editor-shell :deep(.tui-image-editor-header) {
  display: none;
}

.image-editor-shell :deep(.tui-image-editor-main-container) {
  top: 0;
  bottom: 78px;
}

.image-editor-shell :deep(.tui-image-editor-main) {
  top: 0;
}

.image-editor-shell :deep(.tui-image-editor-wrap) {
  top: 0;
}

.image-editor-shell :deep(.tui-image-editor-controls) {
  height: 78px;
  border-top: 1px solid rgba(159, 176, 200, 0.12);
  background: rgba(8, 17, 31, 0.9);
  backdrop-filter: blur(14px);
}

.image-editor-shell :deep(.tui-image-editor-menu > .tui-image-editor-item) {
  margin: 0 6px;
  padding: 10px 10px 4px;
  border-radius: 12px;
}

.image-editor-shell :deep(.tui-image-editor-menu > .tui-image-editor-item.active) {
  background: rgba(248, 250, 252, 0.14);
}

.image-editor-shell :deep(.tui-image-editor-submenu) {
  height: 166px;
  overflow-y: auto;
  overscroll-behavior-y: contain;
}

.image-editor-shell :deep(.tui-image-editor-submenu > div) {
  padding-bottom: 18px;
}

.image-editor-shell :deep(.tui-image-editor-canvas-container) {
  border-radius: 14px;
  overflow: hidden;
}

@media (max-width: 960px) {
  .image-editor-shell {
    min-height: 560px;
    height: min(72dvh, 72vh);
  }

  .image-editor-shell :deep(.tui-image-editor-main-container) {
    bottom: 88px;
  }

  .image-editor-shell :deep(.tui-image-editor-controls) {
    height: 88px;
    overflow-x: auto;
    overscroll-behavior-x: contain;
  }

  .image-editor-shell :deep(.tui-image-editor-menu) {
    padding: 0 16px;
  }
}
</style>
