<!--
  ConfigPanel.vue — 右侧属性配置面板

  功能：
  - Schema 驱动动态表单
  - 支持 text/textarea/number/switch/select/radio/color/image/image-list/nav-list 类型
  - 图片字段支持上传+素材库选择
  - 实时响应 props 变更
  - 空状态引导
-->
<template>
  <aside class="config-panel" :class="{ empty: !schema }">
    <template v-if="schema && comp">
      <div class="panel-header">
        <span class="panel-title">{{ schema.icon }} {{ schema.label }}</span>
        <span class="panel-desc">{{ schema.description }}</span>
      </div>
      <el-divider style="margin:8px 0" />

      <div class="prop-form">
        <template v-for="field in schema.fields" :key="field.key">
          <div v-if="shouldShow(field)" class="prop-field">
            <label class="prop-label">{{ field.label }}</label>
            <div class="prop-control">
              <!-- text -->
              <el-input
                v-if="field.type === 'text'"
                v-model="comp.props[field.key]"
                :placeholder="field.placeholder || ''"
                :maxlength="field.maxlength"
                size="small"
                @update:model-value="emitChange"
              />

              <!-- textarea -->
              <el-input
                v-else-if="field.type === 'textarea'"
                v-model="comp.props[field.key]"
                type="textarea"
                :rows="field.rows || 3"
                :maxlength="field.maxlength"
                size="small"
                @update:model-value="emitChange"
              />

              <!-- number -->
              <el-input-number
                v-else-if="field.type === 'number'"
                v-model="comp.props[field.key]"
                :min="field.min ?? 0"
                :max="field.max ?? 9999"
                :step="field.step || 1"
                size="small"
                controls-position="right"
                style="width:100%"
                @update:model-value="emitChange"
              />

              <!-- switch -->
              <el-switch
                v-else-if="field.type === 'switch'"
                v-model="comp.props[field.key]"
                @update:model-value="emitChange"
              />

              <!-- select -->
              <el-select
                v-else-if="field.type === 'select'"
                v-model="comp.props[field.key]"
                size="small"
                style="width:100%"
                @update:model-value="emitChange"
              >
                <el-option
                  v-for="opt in field.options"
                  :key="typeof opt === 'object' ? opt.value : opt"
                  :label="typeof opt === 'object' ? opt.label : opt"
                  :value="typeof opt === 'object' ? opt.value : opt"
                />
              </el-select>

              <!-- radio -->
              <el-radio-group
                v-else-if="field.type === 'radio'"
                v-model="comp.props[field.key]"
                size="small"
                @update:model-value="emitChange"
              >
                <el-radio v-for="opt in field.options" :key="opt.value" :value="opt.value">
                  {{ opt.label }}
                </el-radio>
              </el-radio-group>

              <!-- color -->
              <el-color-picker
                v-else-if="field.type === 'color'"
                v-model="comp.props[field.key]"
                size="small"
                show-alpha
                @update:model-value="emitChange"
              />

              <!-- image (single) -->
              <div v-else-if="field.type === 'image'" class="image-upload">
                <div v-if="comp.props[field.key]" class="image-preview">
                  <img :src="comp.props[field.key]" alt="preview" />
                  <el-button size="small" circle type="danger" class="img-del" @click="clearImage(field.key)">✕</el-button>
                </div>
                <div class="image-input-row">
                  <el-input v-model="comp.props[field.key]" placeholder="输入图片URL" size="small" @update:model-value="emitChange" />
                  <el-button size="small" @click="openAssetPicker(field.key)" title="从素材库选择">📂</el-button>
                  <el-button size="small" type="primary" @click="triggerUpload(field.key, -1)" title="本地上传">📤</el-button>
                </div>
              </div>

              <!-- image-list -->
              <div v-else-if="field.type === 'image-list'" class="image-list-editor">
                <div v-for="(img, i) in comp.props[field.key]" :key="i" class="image-list-item">
                  <div class="ili-preview">
                    <img v-if="img" :src="img" />
                    <span v-else class="ili-ph">+</span>
                  </div>
                  <el-input v-model="comp.props[field.key][i]" placeholder="图片URL" size="small" @update:model-value="emitChange" />
                  <el-button size="small" @click="openAssetPicker(field.key, i)" title="从素材库选择">📂</el-button>
                  <el-button size="small" @click="triggerUpload(field.key, i)" title="本地上传">📤</el-button>
                  <el-button size="small" type="danger" circle @click="removeImage(field.key, i)">✕</el-button>
                </div>
                <el-button size="small" class="add-img-btn" @click="addImage(field.key)">+ 添加图片</el-button>
              </div>

              <!-- nav-list -->
              <div v-else-if="field.type === 'nav-list'" class="nav-list-editor">
                <div v-for="(item, i) in comp.props[field.key]" :key="i" class="nav-list-item">
                  <div class="nli-header">
                    <span class="nli-index">{{ i + 1 }}</span>
                    <el-button size="small" type="danger" circle @click="removeNavItem(field.key, i)">✕</el-button>
                  </div>
                  <div class="nli-fields">
                    <el-input v-model="item.icon" placeholder="图标(emoji)" size="small" style="width:70px" @update:model-value="emitChange" />
                    <el-input v-model="item.text" placeholder="文字" size="small" @update:model-value="emitChange" />
                    <el-input v-model="item.link" placeholder="链接" size="small" @update:model-value="emitChange" />
                  </div>
                </div>
                <el-button size="small" class="add-nav-btn" @click="addNavItem(field.key)">+ 添加导航项</el-button>
              </div>

              <!-- notice-list（公告列表：多行文本） -->
              <div v-else-if="field.type === 'notice-list'" class="notice-list-editor">
                <div v-for="(txt, i) in comp.props[field.key]" :key="i" class="notice-list-item">
                  <span class="nli-index">{{ i + 1 }}</span>
                  <el-input v-model="comp.props[field.key][i]" placeholder="输入公告内容" size="small" @update:model-value="emitChange" />
                  <el-button size="small" type="danger" circle @click="removeNavItem(field.key, i)">✕</el-button>
                </div>
                <el-button size="small" class="add-nav-btn" @click="addNoticeItem(field.key)">+ 添加公告</el-button>
              </div>

              <!-- datetime（日期时间） -->
              <el-date-picker
                v-else-if="field.type === 'datetime'"
                v-model="comp.props[field.key]"
                type="datetime"
                placeholder="选择结束时间"
                value-format="YYYY-MM-DD HH:mm:ss"
                @change="emitChange"
                style="width:100%"
              />
            </div>

            <!-- 帮助提示 -->
            <span v-if="field.help" class="prop-help">{{ field.help }}</span>
          </div>
        </template>
      </div>
    </template>

    <template v-else>
      <div class="empty-state">
        <div class="empty-icon">⚙️</div>
        <p>点击预览区中的组件</p>
        <p class="empty-sub">右侧将显示该组件的配置项</p>
      </div>
    </template>

    <!-- 素材库选择器弹窗 -->
    <AssetPicker v-model="showAssetPicker" @select="onAssetPicked" />

    <!-- ── 隐藏文件上传 ── -->
    <input
      ref="fileInputRef"
      type="file"
      accept="image/*"
      @change="onFileSelected"
      class="cfg-hidden-upload"
    />
  </aside>
</template>

<script setup>
import { ref, computed } from 'vue'
import { useDesignStore } from '../../../stores/designStore.js'
import { COMPONENT_REGISTRY } from '../utils/componentRegistry.js'
import { shouldShowField } from '../utils/schemaToForm.js'
import AssetPicker from './AssetPicker.vue'

const store = useDesignStore()

const schema = computed(() => store.selectedSchema)
const comp = computed(() => store.selectedComponent)

// 素材选择器状态
const showAssetPicker = ref(false)
const pickerFieldKey = ref('')
const pickerImageIndex = ref(-1)

function openAssetPicker(fieldKey, imageIndex) {
  pickerFieldKey.value = fieldKey
  pickerImageIndex.value = imageIndex !== undefined ? imageIndex : -1
  showAssetPicker.value = true
}

function onAssetPicked(url) {
  if (!comp.value || !url) return
  if (pickerImageIndex.value >= 0) {
    // image-list 模式：替换指定索引
    if (Array.isArray(comp.value.props[pickerFieldKey.value])) {
      comp.value.props[pickerFieldKey.value][pickerImageIndex.value] = url
    }
  } else {
    // 单图模式：直接赋值
    comp.value.props[pickerFieldKey.value] = url
  }
}

// 文件上传（静态隐藏 input，不依赖 display:none）
const fileInputRef = ref(null)
const pendingUpload = ref({ fieldKey: '', imageIndex: -1 })

function triggerUpload(fieldKey, imageIndex) {
  pendingUpload.value = { fieldKey, imageIndex }
  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 (!comp.value) return
      const url = res?.data?.url || res?.url || ''
      if (!url) return
      const { fieldKey, imageIndex } = pendingUpload.value
      if (imageIndex >= 0 && Array.isArray(comp.value.props[fieldKey])) {
        const arr = [...comp.value.props[fieldKey]]
        arr[imageIndex] = url
        comp.value.props[fieldKey] = arr
      } else {
        comp.value.props[fieldKey] = url
      }
      // 同时加入素材库
      fetch('/api/admin/assets', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          Authorization: 'Bearer ' + (token || '')
        },
        body: JSON.stringify({ name: file.name, url, type: 'image' })
      }).catch(() => {})
    })
    .catch(() => {})
    .finally(() => {
      e.target.value = ''
      pendingUpload.value = { fieldKey: '', imageIndex: -1 }
    })
}

function emitChange() {}

function shouldShow(field) {
  return shouldShowField(field, comp.value?.props || {})
}

function clearImage(key) {
  if (comp.value) comp.value.props[key] = ''
  emitChange()
}

function addImage(key) {
  if (comp.value && Array.isArray(comp.value.props[key])) {
    comp.value.props[key].push('')
  }
}

function removeImage(key, index) {
  if (comp.value && Array.isArray(comp.value.props[key])) {
    comp.value.props[key].splice(index, 1)
  }
}

function addNavItem(key) {
  if (comp.value && Array.isArray(comp.value.props[key])) {
    comp.value.props[key].push({ icon: '📄', text: '新项目', link: '' })
  }
}

function removeNavItem(key, index) {
  if (comp.value && Array.isArray(comp.value.props[key])) {
    comp.value.props[key].splice(index, 1)
  }
}

function addNoticeItem(key) {
  if (comp.value && Array.isArray(comp.value.props[key])) {
    comp.value.props[key].push('新公告内容')
  }
}
</script>

<style scoped>
.config-panel {
  width: 290px;
  background: #fff;
  border-left: 1px solid #eee;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  flex-shrink: 0;
}

.config-panel.empty {
  align-items: center;
  justify-content: center;
}

.panel-header {
  padding: 14px 14px 0;
}

.panel-title {
  font-size: 15px;
  font-weight: 700;
  color: #333;
}

.panel-desc {
  font-size: 11px;
  color: #999;
  margin-top: 2px;
  display: block;
}

.prop-form {
  flex: 1;
  overflow-y: auto;
  padding: 4px 14px 20px;
}

.prop-field {
  margin-bottom: 14px;
}

.prop-label {
  display: block;
  font-size: 12px;
  font-weight: 600;
  color: #555;
  margin-bottom: 6px;
}

.prop-control {
  width: 100%;
}

.prop-help {
  display: block;
  font-size: 11px;
  color: #aaa;
  margin-top: 4px;
}

.prop-control :deep(.el-input-number) .el-input-number__decrease,
.prop-control :deep(.el-input-number) .el-input-number__increase {
  width: 24px;
}

.prop-control :deep(.el-switch) {
  --el-switch-on-color: #7C3AED;
}

/* image 单张 */
.image-upload .image-preview {
  position: relative;
  width: 100%;
  height: 80px;
  margin-bottom: 6px;
  border-radius: 6px;
  overflow: hidden;
  background: #f5f5f5;
}

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

.img-del {
  position: absolute;
  top: 4px;
  right: 4px;
  width: 20px;
  height: 20px;
}

.image-input-row {
  display: flex;
  gap: 4px;
}

/* image-list */
.image-list-editor .image-list-item {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 6px;
}

.ili-preview {
  width: 36px;
  height: 36px;
  border-radius: 4px;
  background: #f5f5f5;
  overflow: hidden;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

.ili-preview img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.ili-ph {
  font-size: 18px;
  color: #ccc;
}

.image-list-item .el-input {
  flex: 1;
}

.add-img-btn {
  width: 100%;
  margin-top: 4px;
}

/* nav-list */
.nav-list-editor .nav-list-item {
  border: 1px solid #eee;
  border-radius: 8px;
  padding: 8px;
  margin-bottom: 8px;
}

.notice-list-item {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 8px;
}

.notice-list-item .el-input {
  flex: 1;
}

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

.nli-index {
  font-size: 11px;
  font-weight: 600;
  color: #999;
  background: #f5f5f5;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.nli-fields {
  display: flex;
  gap: 4px;
  flex-wrap: wrap;
}

.nli-fields .el-input {
  min-width: 60px;
  flex: 1;
}

.add-nav-btn {
  width: 100%;
}

/* 空状态 */
.empty-state {
  text-align: center;
  padding: 60px 20px;
  color: #bbb;
}

.empty-state .empty-icon {
  font-size: 36px;
  margin-bottom: 8px;
}

.empty-state p {
  font-size: 13px;
  margin: 4px 0;
}

.empty-sub {
  font-size: 12px;
  opacity: 0.6;
}

/* 隐藏文件上传（不用 display:none，触控兼容） */
.cfg-hidden-upload {
  position: absolute;
  left: 0;
  top: 0;
  width: 0;
  height: 0;
  opacity: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: -1;
}
</style>
