<!--
  AssetPicker.vue — 素材库选择器（弹窗）

  功能：
  - 显示素材库图片列表
  - 上传新图片
  - 点击选择图片
  - 返回图片URL
-->
<template>
  <el-dialog v-model="visible" title="🖼️ 从素材库选择" width="580px" top="5vh" @open="fetchAssets" destroy-on-close>
    <div class="ap-toolbar">
      <div class="ap-upload">
        <el-button type="primary" size="small" @click="triggerUpload">
          <el-icon><Plus /></el-icon>上传图片
        </el-button>
        <el-button size="small" @click="fetchAssets" :icon="Refresh" style="margin-left:8px">刷新</el-button>
      </div>
      <el-input v-model="searchText" placeholder="搜索文件名..." size="small" clearable style="width:200px" prefix-icon="Search" />
    </div>
    <!-- 隐藏文件上传 -->
    <input ref="fileInputRef" type="file" accept="image/*" @change="onFileSelected" class="ap-hidden-input" />

    <div class="ap-grid" v-loading="loading">
      <div
        v-for="a in filteredAssets"
        :key="a.id"
        class="ap-item"
        :class="{ selected: selectedUrl === a.url }"
        @click="selectAsset(a.url)"
      >
        <div class="ap-img-wrap">
          <el-image :src="a.url" fit="cover" style="width:100%;height:100%">
            <template #error><div class="ap-img-err">📷</div></template>
          </el-image>
        </div>
        <div class="ap-name">{{ a.name || a.url.split('/').pop()?.slice(0,15) || '未命名' }}</div>
      </div>
      <div v-if="!loading && filteredAssets.length === 0" class="ap-empty">
        <el-empty :description="searchText ? '未找到匹配素材' : '暂无素材，点击上传'" :image-size="60" />
      </div>
    </div>

    <template #footer>
      <el-button @click="visible = false">取消</el-button>
      <el-button type="primary" :disabled="!selectedUrl" @click="confirm">确 定</el-button>
    </template>
  </el-dialog>
</template>

<script setup>
import { ref, computed } from 'vue'
import { ElMessage } from 'element-plus'
import { Plus, Refresh } from '@element-plus/icons-vue'
import axios from 'axios'

const API = axios.create({ baseURL: '/api/admin' })
API.interceptors.request.use(c => { c.headers.Authorization = 'Bearer ' + localStorage.getItem('admin_token'); return c })

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

const emit = defineEmits(['update:modelValue', 'select'])

const visible = computed({
  get: () => props.modelValue,
  set: v => emit('update:modelValue', v)
})

const assets = ref([])
const loading = ref(false)
const selectedUrl = ref('')
const searchText = ref('')

const filteredAssets = computed(() => {
  if (!searchText.value) return assets.value
  const q = searchText.value.toLowerCase()
  return assets.value.filter(a =>
    (a.name || a.url || '').toLowerCase().includes(q)
  )
})

// 原生文件上传
const fileInputRef = ref(null)

async function fetchAssets() {
  loading.value = true
  try {
    const r = await API.get('/assets')
    assets.value = r.data?.data || []
  } catch { assets.value = [] }
  finally { loading.value = false }
}

function triggerUpload() {
  fileInputRef.value?.click()
}

function onFileSelected(e) {
  const file = e.target?.files?.[0]
  if (!file) return
  const formData = new FormData()
  formData.append('file', file)
  const token = localStorage.getItem('admin_token')
  fetch('/api/upload/image', {
    method: 'POST',
    headers: { Authorization: 'Bearer ' + (token || '') },
    body: formData
  })
    .then(r => r.json())
    .then(res => {
      if (res?.code === 0) {
        const url = res.data?.url || ''
        if (url) {
          fetch('/api/admin/assets', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json', Authorization: 'Bearer ' + (token || '') },
            body: JSON.stringify({ name: file.name, url, type: 'image' })
          }).then(() => fetchAssets()).catch(() => fetchAssets())
          ElMessage.success('上传成功')
        }
      } else {
        ElMessage.error(res?.message || '上传失败')
      }
    })
    .catch(() => ElMessage.error('上传失败'))
    .finally(() => { e.target.value = '' })
}

function selectAsset(url) {
  selectedUrl.value = url
}

function confirm() {
  if (selectedUrl.value) {
    emit('select', selectedUrl.value)
    selectedUrl.value = ''
    visible.value = false
  }
}
</script>

<style scoped>
.ap-toolbar { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; }
.ap-upload { display: flex; align-items: center; }
.ap-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); gap: 10px; max-height: 420px; overflow-y: auto; }
.ap-item { border: 2px solid transparent; border-radius: 8px; overflow: hidden; cursor: pointer; transition: all .15s; background: #fff; }
.ap-item:hover { border-color: #d0c4f0; box-shadow: 0 2px 8px rgba(0,0,0,.06); }
.ap-item.selected { border-color: #7C3AED; box-shadow: 0 0 0 1px rgba(124,58,237,.2); }
.ap-img-wrap { width: 100%; height: 100px; background: #f8f9fa; }
.ap-img-err { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; font-size: 28px; color: #ccc; }
.ap-name { padding: 6px 8px; font-size: 11px; color: #666; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ap-empty { grid-column: 1 / -1; padding: 40px 0; }

.ap-hidden-input { position: absolute; left: 0; top: 0; width: 0; height: 0; opacity: 0; overflow: hidden; pointer-events: none; z-index: -1; }
</style>
