<template>
  <div class="image-management">
    <el-container>
      <!-- 左侧分类树 -->
      <el-aside width="280px" class="category-aside">
        <div class="aside-header-buttons">
          <el-button type="primary" :icon="Plus" @click="handleAddCategory">新增</el-button>
          <el-button :icon="Edit" @click="handleEditSelectedCategory" :disabled="!currentCategory || currentCategory.id === '0'">修改</el-button>
          <el-button type="danger" :icon="Delete" @click="handleDeleteSelectedCategory" :disabled="!currentCategory || currentCategory.id === '0'">删除</el-button>
          <el-button type="warning" :icon="Tickets" @click="handleCategoryBatchAddToTask" style="width: 100%; margin-left: 0; margin-top: 10px;">
            分类批量加入标注任务
          </el-button>
        </div>
        <div class="aside-content">
          <el-tree
            ref="categoryTree"
            :data="categories"
            :props="defaultProps"
            node-key="id"
            default-expand-all
            highlight-current
            @node-click="handleCategoryClick"
          >
            <template #default="{ node, data }">
              <span class="custom-tree-node">
                <span class="label">
                  <el-icon v-if="data.id === '0'"><FolderOpened /></el-icon>
                  <el-icon v-else><Folder /></el-icon>
                  {{ node.label }}
                </span>
              </span>
            </template>
          </el-tree>
        </div>
      </el-aside>

      <!-- 右侧图片列表 -->
      <el-main class="image-main">
        <div class="main-header">
          <div class="header-left">
            <span class="current-category">{{ currentCategoryName }}</span>
          </div>
          <div class="header-right">
            <el-button 
              type="primary" 
              :icon="Tickets" 
              @click="handleBatchAddToTask"
              :disabled="selectedIds.length === 0"
            >
              批量加入标注任务
            </el-button>
            <el-upload
              ref="uploadRef"
              class="upload-btn"
              action="#"
              :auto-upload="false"
              :show-file-list="false"
              multiple
              accept="image/*"
              :on-change="handleFileChange"
            >
              <el-button type="success" :icon="Upload">新增图片</el-button>
            </el-upload>
          </div>
        </div>

        <div class="image-list" v-loading="loading">
          <el-table 
            :data="images" 
            style="width: 100%" 
            height="calc(100vh - 240px)"
            @selection-change="handleSelectionChange"
          >
            <el-table-column type="selection" width="55" />
            <el-table-column label="图片预览" width="120">
              <template #default="scope">
                <el-image 
                  :ref="(el: any) => imageRefs[scope.$index] = el"
                  class="table-image"
                  :src="scope.row.image_url" 
                  :preview-src-list="previewSrcList"
                  :initial-index="scope.$index"
                  fit="cover"
                  preview-teleported
                >
                  <template #error>
                    <div class="image-error">
                      <el-icon><Picture /></el-icon>
                    </div>
                  </template>
                </el-image>
              </template>
            </el-table-column>
            <el-table-column prop="image_name" label="图片名称" min-width="150" show-overflow-tooltip />
            <el-table-column prop="category_name" label="图片分类" width="120" />
            <el-table-column prop="creator_name" label="创建人" width="120" />
            <el-table-column prop="created_time" label="创建时间" width="170">
              <template #default="scope">
                {{ formatDateTime(scope.row.created_time) }}
              </template>
            </el-table-column>
            <el-table-column label="操作" width="120" fixed="right">
              <template #default="scope">
                <el-button type="primary" link @click="handlePreview(scope.$index)">预览</el-button>
                <el-button type="danger" link @click="handleDeleteImage(scope.row)">删除</el-button>
              </template>
            </el-table-column>
            <template #empty>
              <el-empty description="暂无图片" />
            </template>
          </el-table>

          <div class="pagination-container">
            <el-pagination
              v-model:current-page="queryParams.page"
              v-model:page-size="queryParams.page_size"
              :page-sizes="[10, 20, 50, 100]"
              layout="total, sizes, prev, pager, next, jumper"
              :total="total"
              @size-change="handleSizeChange"
              @current-change="handleCurrentChange"
            />
          </div>
        </div>
      </el-main>
    </el-container>

    <!-- 分类弹窗 -->
    <el-dialog
      v-model="categoryDialogVisible"
      :title="categoryForm.id ? '修改分类' : '新增分类'"
      width="400px"
    >
      <el-form :model="categoryForm" label-width="80px">
        <el-form-item label="分类名称" required>
          <el-input v-model="categoryForm.type_name" placeholder="请输入分类名称" />
        </el-form-item>
        <el-form-item label="备注">
          <el-input v-model="categoryForm.remark" type="textarea" placeholder="请输入备注" />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="categoryDialogVisible = false">取消</el-button>
        <el-button type="primary" @click="submitCategory">确定</el-button>
      </template>
    </el-dialog>

    <!-- 图片上传/编辑弹窗 -->
    <el-dialog
      v-model="uploadDialogVisible"
      title="上传图片"
      width="500px"
      :close-on-click-modal="false"
    >
      <div class="upload-list-container">
        <div v-for="(item, index) in uploadFileList" :key="index" class="upload-item">
          <div class="upload-item-preview">
            <el-image :src="item.url" fit="cover" />
          </div>
          <div class="upload-item-info">
            <el-input v-model="item.name" placeholder="请输入图片名称">
              <template #append>{{ item.ext }}</template>
            </el-input>
          </div>
          <div class="upload-item-ops">
            <el-button type="danger" :icon="Delete" circle size="small" @click="removeUploadFile(index)" />
          </div>
        </div>
      </div>
      <template #footer>
        <el-button @click="uploadDialogVisible = false">取消</el-button>
        <el-button type="primary" :loading="uploading" @click="startBatchUpload">开始上传</el-button>
      </template>
    </el-dialog>

    <!-- 加入任务设置弹窗 -->
    <el-dialog v-model="taskDialogVisible" title="加入标注任务" width="450px">
      <el-form :model="taskForm" :rules="taskRules" ref="taskFormRef" label-width="100px">
        <el-form-item label="项目名称" prop="project_name">
          <el-input v-model="taskForm.project_name" placeholder="请输入项目名称" clearable />
        </el-form-item>
        <el-form-item label="任务标签" prop="tags">
          <div class="tag-group">
            <el-tag
              v-for="(tag, index) in taskForm.selectedTags"
              :key="tag.id"
              closable
              @close="handleRemoveTag(index)"
              :type="tag.type === 'category' ? 'warning' : 'primary'"
              class="tag-item"
            >
              {{ tag.name }} <span v-if="tag.type === 'category'" class="tag-type-hint">(分类)</span>
            </el-tag>
            <el-cascader
              :key="cascaderKey"
              v-model="tempTagValue"
              :options="tagTree"
              :props="{ checkStrictly: true, emitPath: false }"
              placeholder="添加标签"
              @change="handleAddTag"
              filterable
              clearable
              class="tag-adder"
            >
              <template #default="{ data }">
                <span>
                  <el-icon v-if="data.type === 'category'" style="margin-right: 4px; color: #E6A23C;">
                    <Folder />
                  </el-icon>
                  <el-icon v-else style="margin-right: 4px; color: #409EFF;">
                    <Tickets />
                  </el-icon>
                  {{ data.label }}
                </span>
              </template>
            </el-cascader>
          </div>
        </el-form-item>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="taskDialogVisible = false">取消</el-button>
          <el-button type="primary" @click="confirmAddTask" :loading="taskAdding">
            确认加入
          </el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, reactive, computed } from 'vue'
import { Plus, Edit, Delete, Upload, Picture, Folder, FolderOpened, Tickets } from '@element-plus/icons-vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { imageApi, type ImageCategory, type ImageItem } from '@/api/image'
import { documentApi } from '@/api/document'
import axios from 'axios'

// --- 数据定义 ---

const loading = ref(false)
const categories = ref<ImageCategory[]>([])
const images = ref<ImageItem[]>([])
const total = ref(0)
const currentCategory = ref<ImageCategory | null>(null)

const defaultProps = {
  children: 'children',
  label: 'type_name'
}

const queryParams = reactive({
  category_id: '',
  page: 1,
  page_size: 10
})

const categoryDialogVisible = ref(false)
const uploadDialogVisible = ref(false)
const uploading = ref(false)
const uploadFileList = ref<any[]>([])
const uploadRef = ref()
const imageRefs = reactive<any>({})
const selectedIds = ref<string[]>([])

// 任务相关状态
const taskAdding = ref(false)
const taskDialogVisible = ref(false)
const tempTagValue = ref<number | null>(null)
const cascaderKey = ref(0)
const taskForm = reactive({
  project_name: '',
  selectedTags: [] as { id: number, name: string, type?: string }[]
})

// 标签相关
const tagTree = ref<any[]>([])

const handleAddTag = (val: any) => {
  if (!val) return
  const id = val
  const node = findTagNode(tagTree.value, id)
  if (!node) return

  // 检查是否是标签分类（type='category'）
  if (node.type === 'category' && node.children && node.children.length > 0) {
    // 如果是标签分类，添加该分类下的所有标签项
    node.children.forEach((child: any) => {
      if (!taskForm.selectedTags.find(t => t.id === child.value)) {
        taskForm.selectedTags.push({ id: child.value, name: child.label, type: child.type })
      }
    })
  } else {
    // 如果是标签项，直接添加
    if (node.type !== 'category' && !taskForm.selectedTags.find(t => t.id === id)) {
      taskForm.selectedTags.push({ id, name: node.label, type: node.type })
    }
  }

  // 清空选择器并增加 key 以强制重置 (清除搜索缓存等)
  tempTagValue.value = null
  cascaderKey.value++
}

const handleRemoveTag = (index: number) => {
  taskForm.selectedTags.splice(index, 1)
}

const findTagName = (nodes: any[], id: number): string | null => {
  for (const node of nodes) {
    if (node.value === id) return node.label
    if (node.children) {
      const name = findTagName(node.children, id)
      if (name) return name
    }
  }
  return null
}

const findTagNode = (nodes: any[], id: number): any | null => {
  for (const node of nodes) {
    if (node.value === id) return node
    if (node.children) {
      const found = findTagNode(node.children, id)
      if (found) return found
    }
  }
  return null
}
const fetchTagTree = async () => {
  try {
    const res = await documentApi.getTagTree()
    if (res.code === '000000' || res.code === 200 || res.code === 0) {
      tagTree.value = formatTagTree(res.data)
    }
  } catch (error: any) {
    console.error('获取标签树失败:', error)
  }
}

const formatTagTree = (data: any[]): any[] => {
  return data.map(node => ({
    value: node.id,
    label: node.name,
    type: node.type,
    children: node.children && node.children.length > 0 ? formatTagTree(node.children) : undefined
  }))
}

const taskRules = {
  project_name: [
    { required: true, message: '请输入项目名称', trigger: 'blur' },
    { min: 2, max: 50, message: '长度在 2 到 50 个字符', trigger: 'blur' }
  ]
}

const taskFormRef = ref()
const isCategoryBatch = ref(false)

const categoryForm = reactive({
  id: '',
  type_name: '',
  parent_id: '0',
  remark: ''
})

const currentCategoryName = computed(() => {
  return currentCategory.value ? currentCategory.value.type_name : '全部分类'
})

const previewSrcList = computed(() => {
  return images.value.map(img => img.image_url).filter(url => !!url)
})

// --- 方法定义 ---

const fetchCategories = async () => {
  try {
    const res = await imageApi.getCategories()
    if (res.code === '000000' || res.code === 0) {
      categories.value = [
        { id: '0', type_name: '全部分类', parent_id: '-1', children: res.data, created_time: '', updated_time: '' }
      ]
    }
  } catch (error: any) {
    console.error('获取分类失败:', error)
  }
}

const fetchImages = async () => {
  loading.value = true
  // 清空引用
  for (const key in imageRefs) {
    delete imageRefs[key]
  }
  try {
    const res = await imageApi.getList(queryParams)
    if (res.code === '000000' || res.code === 0) {
      images.value = res.data.list
      total.value = res.data.total
    }
  } catch (error: any) {
    console.error('获取图片失败:', error)
  } finally {
    loading.value = false
  }
}

const handleSelectionChange = (selection: ImageItem[]) => {
  selectedIds.value = selection.map(item => item.id)
}

const handleBatchAddToTask = async () => {
  if (selectedIds.value.length === 0) return
  
  isCategoryBatch.value = false
  taskForm.project_name = '' // 重置项目名称
  taskForm.selectedTags = [] // 重置标签
  tempTagValue.value = null
  if (taskFormRef.value) {
    taskFormRef.value.clearValidate()
  }
  
  // 获取标签树
  if (tagTree.value.length === 0) {
    await fetchTagTree()
  }
  
  taskDialogVisible.value = true
}

const handleCategoryBatchAddToTask = async () => {
  const categoryId = currentCategory.value?.id === '0' ? '' : (currentCategory.value?.id || '')
  
  try {
    loading.value = true
    const res = await imageApi.categoryBatchCheck(categoryId)
    loading.value = false
    
    //if (res.code !== 0) {
    //  ElMessage.error(res.message || '检查分类失败')
    //  return
    //}

    // 兼容成功错误码 "000000"、0 和 "0" 等情况
    const successCodes = [0, "0", "000000"]
    if (!successCodes.includes(res.code)) {
        ElMessage.error(res.message || '检查分类失败')
        return
    }

    const { image_count, sub_categories } = res.data
    if (image_count === 0) {
      ElMessage.warning('该分类下无图片，无法推送')
      return
    }

    let confirmMsg = `该分类下共有 ${image_count} 张图片。`
    if (sub_categories && sub_categories.length > 0) {
      confirmMsg += `涉及子分类: ${sub_categories.join(', ')}。`
    }
    confirmMsg += '是否继续推送？'

    await ElMessageBox.confirm(confirmMsg, '确认推送', {
      confirmButtonText: '继续',
      cancelButtonText: '取消',
      type: 'info'
    })

    // 通过后才打开弹窗
    isCategoryBatch.value = true
    taskForm.project_name = '' 
    taskForm.selectedTags = []
    tempTagValue.value = null
    if (taskFormRef.value) {
      taskFormRef.value.clearValidate()
    }
    
    // 获取标签树
    if (tagTree.value.length === 0) {
      await fetchTagTree()
    }
    
    taskDialogVisible.value = true
  } catch (error: any) {
    loading.value = false
    if (error !== 'cancel') {
      console.error('分类检查异常:', error)
    }
  }
}

const confirmAddTask = async () => {
  if (!taskFormRef.value) return
  
  try {
    await taskFormRef.value.validate()
  } catch (error: any) {
    return
  }

  taskAdding.value = true
  try {
    const tagNames = taskForm.selectedTags.map(t => t.name)
    let res
    
    if (isCategoryBatch.value) {
      const categoryId = currentCategory.value?.id === '0' ? '' : (currentCategory.value?.id || '')
      res = await imageApi.categoryBatchAddToTask(categoryId, taskForm.project_name, tagNames)
    } else {
      res = await imageApi.batchAddToTask(selectedIds.value, taskForm.project_name, tagNames)
    }

    const { code, message, data } = res
    if ((code === '000000' || code === 0)) {
      let successMsg = message || '批量加入任务成功'
      if (isCategoryBatch.value && data) {
        if (data.image_count === 0) {
          ElMessage.warning('该分类下无图片，无法推送')
          taskAdding.value = false
          return
        }
        if (data.sub_categories && data.sub_categories.length > 0) {
          successMsg = `成功推送 ${data.image_count} 张图片。涉及子分类: ${data.sub_categories.join(', ')}`
        }
      }
      
      ElMessage.success(successMsg)
      selectedIds.value = []
      taskDialogVisible.value = false
      fetchImages()
    } else {
      ElMessage.error(message || '操作失败')
    }
  } catch (error: any) {
    console.error('批量加入任务失败:', error)
    ElMessage.error('操作异常')
  } finally {
    taskAdding.value = false
  }
}

const handleCategoryClick = (data: ImageCategory) => {
  currentCategory.value = data
  queryParams.category_id = data.id === '0' ? '' : data.id
  queryParams.page = 1
  fetchImages()
}

const handleEditSelectedCategory = () => {
  if (currentCategory.value && currentCategory.value.id !== '0') {
    handleEditCategory(currentCategory.value)
  }
}

const handleDeleteSelectedCategory = () => {
  if (currentCategory.value && currentCategory.value.id !== '0') {
    handleDeleteCategory(currentCategory.value)
  }
}

const handleAddCategory = () => {
  categoryForm.id = ''
  categoryForm.type_name = ''
  categoryForm.remark = ''
  categoryForm.parent_id = currentCategory.value?.id === '0' ? '0' : (currentCategory.value?.id || '0')
  categoryDialogVisible.value = true
}

const handleEditCategory = (data: ImageCategory) => {
  categoryForm.id = data.id
  categoryForm.type_name = data.type_name
  categoryForm.remark = data.remark || ''
  categoryForm.parent_id = data.parent_id
  categoryDialogVisible.value = true
}

const handleDeleteCategory = (data: ImageCategory) => {
  ElMessageBox.confirm(`确定要删除分类 "${data.type_name}" 吗？`, '提示', {
    type: 'warning'
  }).then(async () => {
    try {
      const res = await imageApi.deleteCategory(data.id)
      if (res.code === '000000' || res.code === 0) {
        ElMessage.success('删除成功')
        fetchCategories()
      } else {
        ElMessage.error(res.message)
      }
    } catch (error: any) {
      ElMessage.error(error.message || '删除失败')
    }
  })
}

const submitCategory = async () => {
  if (!categoryForm.type_name) {
    return ElMessage.warning('请输入分类名称')
  }
  try {
    let res
    if (categoryForm.id) {
      res = await imageApi.updateCategory(categoryForm.id, categoryForm)
    } else {
      res = await imageApi.addCategory(categoryForm)
    }
    if (res.code === '000000' || res.code === 0) {
      ElMessage.success(categoryForm.id ? '更新成功' : '新增成功')
      categoryDialogVisible.value = false
      fetchCategories()
    } else {
      ElMessage.error(res.message)
    }
  } catch (error: any) {
    ElMessage.error(error.message || '操作失败')
  }
}

const handleFileChange = (file: any) => {
  const categoryId = queryParams.category_id || '0'
  if (categoryId === '0') {
    ElMessage.warning('请先在左侧选择一个具体的分类再上传图片')
    return
  }

  const name = file.name.replace(/\.[^/.]+$/, "")
  const ext = file.name.split('.').pop()
  
  uploadFileList.value.push({
    file: file.raw,
    name: name,
    ext: `.${ext}`,
    url: URL.createObjectURL(file.raw)
  })
  
  uploadDialogVisible.value = true
}

const removeUploadFile = (index: number) => {
  uploadFileList.value.splice(index, 1)
  if (uploadFileList.value.length === 0) {
    uploadDialogVisible.value = false
  }
}

const startBatchUpload = async () => {
  if (uploadFileList.value.length === 0) return
  
  uploading.value = true
  let successCount = 0
  let failCount = 0
  
  const categoryId = queryParams.category_id

  for (const item of uploadFileList.value) {
    try {
      // 1. 获取预签名 URL
      const res = await imageApi.getUploadUrl(item.file.name, item.file.type || 'application/octet-stream')
      //if (res.code !== 0) throw new Error(res.message)
      // 兼容成功错误码 "000000"、0 和 "0" 等情况
      const successCodes = [0, "0", "000000"]
      if (!successCodes.includes(res.code)) throw new Error(res.message)

      const { upload_url, file_url } = res.data

      // 2. 直接上传到 MinIO
      await axios.put(upload_url, item.file, {
        headers: { 'Content-Type': item.file.type || 'application/octet-stream' }
      })

      // 3. 保存到数据库 (使用修改后的名字)
      await imageApi.add({
        image_name: item.name,
        image_url: file_url,
        image_type: categoryId,
        description: ''
      })
      
      successCount++
    } catch (error: any) {
      console.error(`图片 ${item.name} 上传失败:`, error)
      failCount++
    }
  }
  
  uploading.value = false
  uploadDialogVisible.value = false
  uploadFileList.value = []
  
  if (failCount === 0) {
    ElMessage.success(`成功上传 ${successCount} 张图片`)
  } else {
    ElMessage.warning(`上传完成：成功 ${successCount}，失败 ${failCount}`)
  }
  
  fetchImages()
}

const handleDeleteImage = (row: ImageItem) => {
  ElMessageBox.confirm(`确定要删除图片 "${row.image_name}" 吗？`, '提示', {
    type: 'warning'
  }).then(async () => {
    try {
      const res = await imageApi.delete(row.id)
      if (res.code === '000000' || res.code === 0) {
        ElMessage.success('删除成功')
        fetchImages()
      } else {
        ElMessage.error(res.message)
      }
    } catch (error: any) {
      ElMessage.error(error.message || '删除失败')
    }
  })
}

const handlePreview = (index: number) => {
  if (imageRefs[index]) {
    // 触发 el-image 的预览
    const el = imageRefs[index].$el.querySelector('img')
    if (el) el.click()
  }
}

const handleSizeChange = (val: number) => {
  queryParams.page_size = val
  fetchImages()
}

const handleCurrentChange = (val: number) => {
  queryParams.page = val
  fetchImages()
}

const formatDateTime = (dateStr: string) => {
  if (!dateStr) return '-'
  const date = new Date(dateStr)
  return date.toLocaleString()
}

onMounted(() => {
  fetchCategories()
  fetchImages()
})
</script>

<style scoped>
.tag-group {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  min-height: 32px;
}

.tag-item {
  margin: 2px 0;
}

.tag-type-hint {
  font-size: 12px;
  margin-left: 4px;
  opacity: 0.7;
}

.tag-adder {
  width: 120px;
}

.image-management {
  height: calc(100vh - 120px);
  background-color: #f5f7fa;
  padding: 20px;
}

.category-aside {
  background-color: #fff;
  border-radius: 8px;
  margin-right: 20px;
  display: flex;
  flex-direction: column;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
}

.aside-header-buttons {
  padding: 20px;
  border-bottom: 1px solid #f0f2f5;
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}

.aside-header-buttons .el-button {
  margin: 0;
  flex: 1;
}

.aside-content {
  flex: 1;
  padding: 10px;
  overflow-y: auto;
}

.custom-tree-node {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 14px;
  padding-right: 8px;
}

.custom-tree-node .label {
  display: flex;
  align-items: center;
  gap: 5px;
}

.custom-tree-node .ops {
  display: none;
  gap: 8px;
  color: #909399;
}

.el-tree-node__content:hover .ops {
  display: flex;
}

.ops .el-icon:hover {
  color: #409eff;
}

.image-main {
  background-color: #fff;
  border-radius: 8px;
  padding: 20px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
  display: flex;
  flex-direction: column;
}

.main-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
}

.header-right {
  display: flex;
  align-items: center;
  gap: 12px;
}

.current-category {
  font-size: 18px;
  font-weight: bold;
  color: #303133;
}

.image-list {
  flex: 1;
}

.table-image {
  width: 80px;
  height: 60px;
  border-radius: 4px;
}

.image-error {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 100%;
  background: #f5f7fa;
  color: #909399;
  font-size: 20px;
}

.upload-list-container {
  max-height: 400px;
  overflow-y: auto;
  padding: 10px;
}

.upload-item {
  display: flex;
  align-items: center;
  gap: 15px;
  padding: 10px;
  border-bottom: 1px solid #f0f2f5;
}

.upload-item:last-child {
  border-bottom: none;
}

.upload-item-preview {
  width: 60px;
  height: 60px;
  border-radius: 4px;
  overflow: hidden;
  flex-shrink: 0;
}

.upload-item-info {
  flex: 1;
}

.upload-item-ops {
  flex-shrink: 0;
}

.pagination-container {
  margin-top: 20px;
  display: flex;
  justify-content: flex-end;
}

.upload-btn {
  display: inline-block;
}
</style>
