<template>
  <Dialog v-model="dialogVisible" :title="dialogTitle" width="92%" :fullscreen="false" top="4vh">
    <div class="hiprint-preview">
      <div class="hiprint-toolbar">
        <div class="hiprint-paper">
          <el-button
            v-for="(value, type) in paperTypes"
            :key="type"
            size="small"
            :type="curPaperType === type ? 'primary' : 'default'"
            @click="setPaper(type, value)"
          >
            {{ type }}
          </el-button>
          <el-popover placement="bottom-start" :width="260" trigger="click" v-model:visible="paperPopVisible">
            <template #reference>
              <el-button size="small" :type="curPaperType === 'other' ? 'primary' : 'default'">自定义纸张</el-button>
            </template>
            <div class="paper-pop">
              <div class="paper-pop-title">设置纸张宽高(mm)</div>
              <div class="paper-pop-form">
                <el-input-number v-model="paperWidth" :precision="1" :min="1" controls-position="right" />
                <span>x</span>
                <el-input-number v-model="paperHeight" :precision="1" :min="1" controls-position="right" />
              </div>
              <el-button class="mt-8px" size="small" type="primary" @click="setPaperOther">确定</el-button>
            </div>
          </el-popover>
        </div>
        <div class="hiprint-zoom">
          <el-button size="small" @click="changeScale(false)">
            <Icon icon="ep:zoom-out" />
          </el-button>
          <div class="zoom-value">{{ (scaleValue * 100).toFixed(0) }}%</div>
          <el-button size="small" @click="changeScale(true)">
            <Icon icon="ep:zoom-in" />
          </el-button>
        </div>
        <el-button type="primary" size="small" :loading="saveLoading" @click="handleSave">
          <Icon icon="ep:check" class="mr-4px" />
          {{ t('common.save') }}
        </el-button>
      </div>

      <div class="hiprint-body">
        <div class="hiprint-left">
          <div class="hiprint-title">基础元素</div>
          <div :id="dragContainerId" class="hiprint-drag-wrap">
            <div v-for="item in baseElements" :key="item.tid" class="ep-draggable-item hiprint-item" :tid="item.tid">
              <span>{{ item.label }}</span>
            </div>
          </div>
          <div v-if="barcodeElements.length" class="hiprint-title" style="margin-top: 8px">条码类型</div>
          <div v-if="barcodeElements.length" :id="barcodeDragContainerId" class="hiprint-drag-wrap">
            <div v-for="item in barcodeElements" :key="item.tid" class="ep-draggable-item hiprint-item" :tid="item.tid">
              <span style="display: block; text-align: center;" v-html="item.label"></span>
            </div>
          </div>
        </div>
        <div class="hiprint-center">
          <div :id="designerContainerId"></div>
        </div>
        <div class="hiprint-right">
          <div :id="settingContainerId"></div>
        </div>
      </div>
    </div>
  </Dialog>
</template>

<script setup lang="ts">
import { defaultElementTypeProvider, hiprint } from 'vue-plugin-hiprint'
import { PrintTemplateApi } from '@/api/mes/printtemplate'
import { getSimpleDictDataList } from '@/api/system/dict/dict.data'
import qrCodeImg from '@/assets/imgs/qrCode.png'

const { t } = useI18n()
const message = useMessage()

const baseElements = [
  { tid: 'defaultModule.text', label: '文本' },
  { tid: 'defaultModule.image', label: '图片' },
  { tid: 'qrcodeModule.qrcode', label: '二维码' },
  { tid: 'defaultModule.longText', label: '长文' },
  { tid: 'defaultModule.table', label: '表格' },
  { tid: 'defaultModule.hline', label: '横线' },
  { tid: 'defaultModule.vline', label: '竖线' },
  { tid: 'defaultModule.rect', label: '矩形' },
  { tid: 'defaultModule.oval', label: '圆形' }
]

const barcodeElements = ref<{ tid: string; label: string }[]>([])
const barcodeDictData = ref<any[]>([])

const loadBarcodeDictData = async () => {
  try {
    const res = await getSimpleDictDataList()
    const filtered = (res || []).filter((item: any) => item.dictType === 'print_template_type')
    barcodeDictData.value = filtered
    const elements: { tid: string; label: string }[] = []
    filtered.forEach((item: any) => {
      elements.push({ tid: `barcodeModule.${item.value}_qrcode`, label: `${item.label}<br/>二维码` })
      elements.push({ tid: `barcodeModule.${item.value}_text`, label: `${item.label}<br/>文本` })
    })
    barcodeElements.value = elements
  } catch (e) {
    console.error('加载条码字典数据失败', e)
  }
}

const barcodeProvider = function () {
  const addElementTypes = function (context: any) {
    context.removePrintElementTypes('barcodeModule')
    if (!barcodeDictData.value.length) return
    const groups: any[] = []
    barcodeDictData.value.forEach((item: any) => {
      const remark = item.remark || ''
      const parts = remark.split(',').map((s: string) => s.trim())
      const qrcodeField = parts[0] || ''
      const textField = parts[1] || ''
      groups.push(
        new hiprint.PrintElementTypeGroup(item.label, [
          {
            tid: `barcodeModule.${item.value}_qrcode`,
            title: `${item.label}`,
            type: 'image',
            options: {
              field: qrcodeField,
              src: qrCodeImg,
              testData: qrCodeImg,
              width: 80,
              height: 80,
              title: `${item.label}<br/>二维码`
            }
          },
          {
            tid: `barcodeModule.${item.value}_text`,
            title: `${item.label}`,
            type: 'text',
            options: {
              field: textField,
              testData: '',
              title: `${item.label}<br/>文本`,
              fontSize: 10,
              textAlign: 'center',
              width: 80,
              height: 16
            }
          }
        ])
      )
    })
    context.addPrintElementTypes('barcodeModule', groups)
  }
  return { addElementTypes }
}

const qrcodeProvider = function () {
  const addElementTypes = function (context: any) {
    context.removePrintElementTypes('qrcodeModule')
    context.addPrintElementTypes('qrcodeModule', [
      new hiprint.PrintElementTypeGroup('二维码', [
        {
          tid: 'qrcodeModule.qrcode',
          title: '二维码',
          type: 'image',
          options: {
            field: '',
            src: qrCodeImg,
            testData: qrCodeImg,
            width: 80,
            height: 80,
            title: '二维码'
          }
        }
      ])
    ])
  }
  return { addElementTypes }
}

const dialogVisible = ref(false)
const dialogTitle = ref('模板配置')
const saveLoading = ref(false)
const currentRow = ref<any>(null)
const currentTemplateJson = ref<Record<string, any> | undefined>(undefined)

const instanceId = `hiprint-designer-${Math.random().toString(36).slice(2)}`
const dragContainerId = `${instanceId}-drag`
const barcodeDragContainerId = `${instanceId}-barcode-drag`
const designerContainerId = `${instanceId}-designer`
const settingContainerId = `${instanceId}-setting`

const paperTypes = {
  A3: { width: 420, height: 296.6 },
  A4: { width: 210, height: 296.6 },
  A5: { width: 210, height: 147.6 },
  B3: { width: 500, height: 352.6 },
  B4: { width: 250, height: 352.6 },
  B5: { width: 250, height: 175.6 }
}
const curPaper = ref({
  type: 'A4',
  width: 210,
  height: 296.6
})
const paperPopVisible = ref(false)
const paperWidth = ref(220)
const paperHeight = ref(80)
const curPaperType = computed(() => {
  let type = 'other'
  for (const [key, value] of Object.entries(paperTypes)) {
    if (value.width === curPaper.value.width && value.height === curPaper.value.height) {
      type = key
      break
    }
  }
  return type
})

const scaleValue = ref(1)
const scaleMax = 5
const scaleMin = 0.5

let hiprintInited = false
let hiprintTemplate: any

const ensureInit = () => {
  if (hiprintInited) {
    return
  }
  hiprint.init({
    providers: [new defaultElementTypeProvider(), qrcodeProvider(), barcodeProvider()]
  })
  hiprintInited = true
}

const buildLeftElement = () => {
  const jquery = (window as any).$
  if (!jquery) {
    message.warning('未检测到 jQuery，无法加载拖拽元素')
    return
  }
  hiprint.PrintElementTypeManager.buildByHtml(jquery(`#${dragContainerId} .ep-draggable-item`))
  if (barcodeElements.value.length) {
    hiprint.PrintElementTypeManager.buildByHtml(jquery(`#${barcodeDragContainerId} .ep-draggable-item`))
  }
}

const buildDesigner = () => {
  const jquery = (window as any).$
  if (!jquery) {
    message.warning('未检测到 jQuery，无法初始化打印设计器')
    return
  }
  jquery(`#${designerContainerId}`).empty()
  const template = currentTemplateJson.value || undefined
  hiprintTemplate = new hiprint.PrintTemplate({
    template,
    settingContainer: `#${settingContainerId}`
  })
  hiprintTemplate.design(`#${designerContainerId}`)
  setPaper(curPaperType.value, { width: curPaper.value.width, height: curPaper.value.height })
  hiprintTemplate.zoom(scaleValue.value)
}

const setPaper = (type: string, value: { width: number; height: number }) => {
  if (!hiprintTemplate) {
    return
  }
  const width = Number(value.width)
  const height = Number(value.height)
  curPaper.value = { type, width, height }
  hiprintTemplate.setPaper(width, height)
}

const setPaperOther = () => {
  paperPopVisible.value = false
  setPaper('other', { width: Number(paperWidth.value), height: Number(paperHeight.value) })
}

const changeScale = (isZoomIn: boolean) => {
  if (!hiprintTemplate) {
    return
  }
  let nextScale = scaleValue.value
  if (isZoomIn) {
    nextScale += 0.1
    if (nextScale > scaleMax) nextScale = scaleMax
  } else {
    nextScale -= 0.1
    if (nextScale < scaleMin) nextScale = scaleMin
  }
  scaleValue.value = nextScale
  hiprintTemplate.zoom(nextScale)
}

const handleSave = async () => {
  if (!hiprintTemplate) {
    return
  }
  const templateJson = hiprintTemplate.getJson()
  saveLoading.value = true
  try {
    await PrintTemplateApi.updatePrintTemplate({
      id: currentRow.value.id,
      templateCode: currentRow.value.templateCode,
      templateName: currentRow.value.templateName,
      templateType: currentRow.value.templateType,
      templateJson: JSON.stringify(templateJson),
    } as any)
    message.success(t('common.updateSuccess'))
    dialogVisible.value = false
    emit('success')
  } finally {
    saveLoading.value = false
  }
}

const resetState = () => {
  scaleValue.value = 1
  curPaper.value = {
    type: 'A4',
    width: 210,
    height: 296.6
  }
  paperWidth.value = 220
  paperHeight.value = 80
  paperPopVisible.value = false
}

const open = async (row: any) => {
  currentRow.value = row
  dialogTitle.value = `${t('TemplateManagement.PrintTemplate.designTitle')}${row.templateName ? ' - ' + row.templateName : ''}`
  currentTemplateJson.value = row.templateJson ? (typeof row.templateJson === 'string' ? JSON.parse(row.templateJson) : row.templateJson) : undefined
  resetState()
  await loadBarcodeDictData()
  dialogVisible.value = true
  await nextTick()
  ensureInit()
  buildLeftElement()
  buildDesigner()
}

const emit = defineEmits(['success'])

defineExpose({ open })
</script>

<style scoped lang="scss">
.hiprint-preview {
  width: 100%;
}

.hiprint-toolbar {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 12px;
}

.hiprint-paper {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}

.hiprint-zoom {
  display: flex;
  align-items: center;
  gap: 4px;
}

.zoom-value {
  width: 56px;
  text-align: center;
  font-size: 13px;
  color: var(--el-text-color-regular);
}

.paper-pop-title {
  font-size: 14px;
  font-weight: 600;
}

.paper-pop-form {
  margin-top: 8px;
  display: flex;
  align-items: center;
  gap: 8px;
}

.hiprint-body {
  height: 75vh;
  display: grid;
  grid-template-columns: 220px 1fr 300px;
  gap: 12px;
}

.hiprint-left,
.hiprint-center,
.hiprint-right {
  background: var(--el-bg-color);
  border: 1px solid var(--el-border-color-light);
  border-radius: 8px;
  overflow: auto;
}

.hiprint-center {
  padding: 16px;
}

.hiprint-right {
  padding: 12px;
}

.hiprint-title {
  padding: 10px 10px 0;
  font-weight: 600;
}

.hiprint-drag-wrap {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
  padding: 10px;
}

.hiprint-item {
  min-height: 56px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 6px;
  border: 1px solid var(--el-border-color);
  background: var(--el-fill-color-light);
  color: var(--el-text-color-primary);
  cursor: grab;
}
</style>
