<template>
  <el-dialog
      v-model="visible"
      title="以图搜图"
      width="680px"
      destroy-on-close
      :close-on-click-modal="false"
      @close="handleClose"
  >
    <div class="image-search-body">
      <!-- 左侧：图片上传 -->
      <div class="upload-section">
        <el-upload
            ref="uploadRef"
            class="image-uploader"
            drag
            :auto-upload="false"
            :show-file-list="false"
            accept="image/*"
            :on-change="handleFileChange"
        >
          <div v-if="!previewUrl" class="upload-placeholder">
            <el-icon class="upload-icon" :size="48"><UploadFilled /></el-icon>
            <div class="upload-text">点击或拖拽图片上传</div>
            <div class="upload-hint">支持 jpg/png/gif 等格式</div>
          </div>
          <div v-else class="preview-wrapper">
            <img :src="previewUrl" class="preview-image" />
            <div class="preview-overlay">
              <el-button size="small" @click.stop="clearImage">重新选择</el-button>
            </div>
          </div>
        </el-upload>

        <div v-if="searching" class="loading-tip">
          <el-icon class="is-loading"><Loading /></el-icon>
          <span>正在识别图片并检索...</span>
        </div>
      </div>

      <!-- 右侧：搜索结果 -->
      <div class="result-section">
        <div v-if="!searched && !searching" class="result-empty">
          <el-icon :size="40" color="#c0c4cc"><Picture /></el-icon>
          <p>上传图片后自动检索</p>
        </div>

        <div v-else-if="searched && results.length === 0" class="result-empty">
          <el-icon :size="40" color="#c0c4cc"><WarningFilled /></el-icon>
          <p>未找到相似物料</p>
          <p class="result-hint">请尝试更换图片</p>
        </div>

        <div v-else class="result-list">
          <div
              v-for="(item, index) in results"
              :key="item.product_id"
              class="result-item"
          >
            <div class="item-rank">{{ index + 1 }}</div>
            <div class="item-image">
              <img
                  v-if="item.image_url"
                  :src="fullImageUrl(item.image_url)"
                  @error="handleImgError($event)"
              />
              <div v-else class="image-placeholder">
                <el-icon :size="24" color="#c0c4cc"><Picture /></el-icon>
              </div>
            </div>
            <div class="item-info">
              <div class="item-name">{{ item.product_name || '未命名物料' }}</div>
              <div class="item-spec">{{ item.spec_model || '无规格' }}</div>
              <div class="item-similarity">
                <span class="similarity-label">相似度</span>
                <span class="similarity-value">{{ (item.similarity * 100).toFixed(2) }}%</span>
              </div>
            </div>
            <div class="item-actions">
              <el-button
                  type="primary"
                  size="small"
                  @click="handleUse(item)"
              >
                使用此物料
              </el-button>
              <el-button
                  size="small"
                  @click="handleView(item)"
              >
                查看详情
              </el-button>
            </div>
          </div>
        </div>
      </div>
    </div>

    <template #footer>
      <el-button @click="handleClose">关闭</el-button>
    </template>
  </el-dialog>
</template>

<script setup lang="ts">
import { ref, watch } from 'vue'
import { UploadFilled, Loading, Picture, WarningFilled } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import { imageSearch, type ImageSearchItem } from '@/api/common/upload'

interface Props {
  modelValue: boolean
}

const props = defineProps<Props>()

const emit = defineEmits<{
  (e: 'update:modelValue', val: boolean): void
  (e: 'use', item: ImageSearchItem): void
  (e: 'view', item: ImageSearchItem): void
}>()

const visible = ref(props.modelValue)
const uploadRef = ref()
const previewUrl = ref('')
const currentFile = ref<File | null>(null)
const searching = ref(false)
const searched = ref(false)
const results = ref<ImageSearchItem[]>([])

watch(() => props.modelValue, (val) => {
  visible.value = val
  if (!val) {
    resetState()
  }
})

watch(visible, (val) => {
  emit('update:modelValue', val)
})

const handleFileChange = (uploadFile: any) => {
  const file = uploadFile.raw
  if (!file) return

  // 校验格式
  const allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/bmp']
  if (!allowedTypes.includes(file.type)) {
    ElMessage.warning('仅支持 jpg/png/gif/webp/bmp 格式')
    return
  }

  currentFile.value = file
  previewUrl.value = URL.createObjectURL(file)

  // 自动触发搜索
  doSearch(file)
}

const doSearch = async (file: File) => {
  if (searching.value) return

  searching.value = true
  searched.value = false
  results.value = []

  try {
    const res = await imageSearch(file)
    if (res.code === 200) {
      results.value = res.data || []
    } else {
      ElMessage.error(res.msg || '检索失败')
    }
  } catch (err: any) {
    console.error('image search error:', err)
    ElMessage.error(err.message || '网络错误，请重试')
  } finally {
    searching.value = false
    searched.value = true
  }
}

const clearImage = () => {
  previewUrl.value = ''
  currentFile.value = null
  results.value = []
  searched.value = false
  uploadRef.value?.clearFiles()
}

const fullImageUrl = (path: string) => {
  if (!path) return ''
  // 相对路径转完整 URL
  if (path.startsWith('http')) return path
  const baseUrl = import.meta.env.VITE_API_BASE_URL || window.location.origin
  return baseUrl + path
}

const handleImgError = (e: Event) => {
  const img = e.target as HTMLImageElement
  img.style.display = 'none'
}

const handleUse = (item: ImageSearchItem) => {
  emit('use', item)
  handleClose()
}

const handleView = (item: ImageSearchItem) => {
  emit('view', item)
}

const handleClose = () => {
  visible.value = false
}

const resetState = () => {
  previewUrl.value = ''
  currentFile.value = null
  searching.value = false
  searched.value = false
  results.value = []
}
</script>

<style scoped>
.image-search-body {
  display: flex;
  gap: 24px;
  min-height: 380px;
}

/* ── 左侧上传区 ── */
.upload-section {
  flex: 0 0 220px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.image-uploader {
  width: 100%;
}

:deep(.el-upload) {
  width: 100%;
}

:deep(.el-upload-dragger) {
  width: 100%;
  height: 280px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #fafafa;
  border: 2px dashed #dcdfe6;
  border-radius: 8px;
  transition: border-color 0.2s;
}

:deep(.el-upload-dragger:hover) {
  border-color: #409eff;
}

.upload-placeholder {
  text-align: center;
  color: #909399;
}

.upload-icon {
  color: #c0c4cc;
  margin-bottom: 12px;
}

.upload-text {
  font-size: 14px;
  font-weight: 500;
  margin-bottom: 6px;
}

.upload-hint {
  font-size: 12px;
  color: #c0c4cc;
}

.preview-wrapper {
  position: relative;
  width: 100%;
  height: 280px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 8px;
  overflow: hidden;
}

.preview-image {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

.preview-overlay {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  padding: 10px;
  background: rgba(0, 0, 0, 0.5);
  text-align: center;
}

.preview-overlay .el-button {
  color: #fff;
  border-color: rgba(255, 255, 255, 0.6);
}

.loading-tip {
  display: flex;
  align-items: center;
  gap: 8px;
  color: #409eff;
  font-size: 13px;
}

/* ── 右侧结果区 ── */
.result-section {
  flex: 1;
  overflow-y: auto;
}

.result-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 280px;
  color: #909399;
  text-align: center;
}

.result-empty p {
  margin: 8px 0 0;
  font-size: 14px;
}

.result-hint {
  font-size: 12px !important;
  color: #c0c4cc;
}

.result-list {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.result-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 12px;
  background: #f5f7fa;
  border-radius: 8px;
  transition: background 0.2s;
}

.result-item:hover {
  background: #ecf5ff;
}

.item-rank {
  flex: 0 0 24px;
  width: 24px;
  height: 24px;
  background: #409eff;
  color: #fff;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  font-weight: 700;
}

.item-image {
  flex: 0 0 60px;
  width: 60px;
  height: 60px;
  border-radius: 6px;
  overflow: hidden;
  background: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid #ebeef5;
}

.item-image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.image-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
}

.item-info {
  flex: 1;
  min-width: 0;
}

.item-name {
  font-size: 14px;
  font-weight: 600;
  color: #303133;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.item-spec {
  font-size: 12px;
  color: #909399;
  margin-top: 4px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.item-similarity {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 6px;
}

.similarity-label {
  font-size: 12px;
  color: #909399;
}

.similarity-value {
  font-size: 14px;
  font-weight: 700;
  color: #67c23a;
}

.item-actions {
  display: flex;
  flex-direction: column;
  gap: 6px;
  flex: 0 0 auto;
}
</style>