<template>
  <Dialog :title="dialogTitle" v-model="dialogVisible">
    <el-form ref="formRef" :model="formData" :rules="formRules" label-width="100px" v-loading="formLoading">
      <el-form-item label="角色头像" prop="avatarUrl">
        <div class="flex items-center gap-12px">
          <el-avatar v-if="formData.avatarUrl" :src="formData.avatarUrl" :size="50" />
          <el-button type="primary" plain @click="avatarInputRef?.click()">
            {{ formData.avatarUrl ? '重新上传' : '选择图片' }}
          </el-button>
          <el-button v-if="formData.avatarUrl" type="danger" plain @click="formData.avatarUrl = undefined">
            删除
          </el-button>
          <input ref="avatarInputRef" type="file" accept="image/*" class="hidden" @change="onAvatarFileChange" />
        </div>
        <!-- 头像裁剪弹窗 -->
        <Dialog v-model="cropperVisible" title="裁剪头像（50 x 50）" width="800px" :canFullscreen="false">
          <div class="flex gap-20px">
            <div class="flex-1">
              <CropperImage v-if="avatarCropSrc" :src="avatarCropSrc" height="300px"
                :options="{ aspectRatio: 1, viewMode: 1 }" @ready="onCropperReady" @cropend="onCropend" />
            </div>
            <div class="flex flex-col items-center justify-center">
              <div class="w-50px h-50px overflow-hidden border border-gray-300 rounded-full">
                <img v-if="avatarPreview" :src="avatarPreview" class="w-full h-full" />
              </div>
              <span class="mt-8px text-12px text-gray-400">200x 200 预览</span>
            </div>
          </div>
          <template #footer>
            <el-button @click="cropperVisible = false">取消</el-button>
            <el-button type="primary" :loading="avatarUploading" @click="confirmCropAvatar">
              确认上传
            </el-button>
          </template>
        </Dialog>
      </el-form-item>
      <el-form-item label="角色封面图" prop="coverImageUrl">
        <div class="flex items-center gap-12px">
          <el-image v-if="formData.coverImageUrl" :src="formData.coverImageUrl" fit="cover" class="cover-image-preview"
            :preview-src-list="[formData.coverImageUrl]" />
          <el-button type="primary" plain @click="coverInputRef?.click()">
            {{ formData.coverImageUrl ? '重新上传' : '选择图片' }}
          </el-button>
          <el-button v-if="formData.coverImageUrl" type="danger" plain @click="formData.coverImageUrl = undefined">
            删除
          </el-button>
          <input ref="coverInputRef" type="file" accept="image/*" class="hidden" @change="onCoverFileChange" />
        </div>
      </el-form-item>
      <el-form-item label="性别" prop="gender">
        <el-input v-model="formData.gender" placeholder="male / female / other" />
      </el-form-item>
      <el-form-item label="年龄段" prop="ageRange">
        <el-input v-model="formData.ageRange" placeholder="如：20s、25-30" />
      </el-form-item>
      <el-form-item label="性格标签" prop="personalityTags">
        <el-input v-model="formData.personalityTags" placeholder="如：温柔、黏人、治愈" />
      </el-form-item>
      <el-form-item label="说话风格" prop="speakingStyle">
        <el-input v-model="formData.speakingStyle" placeholder="如：撒娇型、理性型、活泼型" />
      </el-form-item>
      <el-form-item label="系统Prompt" prop="systemPrompt">
        <el-input type="textarea" v-model="formData.systemPrompt" placeholder="定义角色核心人设" />
      </el-form-item>
      <el-form-item label="状态" prop="status">
        <el-radio-group v-model="formData.status">
          <el-radio :value="1">上线</el-radio>
          <el-radio :value="0">下线</el-radio>
        </el-radio-group>
      </el-form-item>
      <el-form-item label="可见性" prop="visibility">
        <el-select v-model="formData.visibility" placeholder="请选择可见性">
          <el-option label="公开" :value="1" />
          <el-option label="内测" :value="2" />
          <el-option label="隐藏" :value="3" />
        </el-select>
      </el-form-item>
      <el-form-item label="排序权重" prop="sortOrder">
        <el-input v-model="formData.sortOrder" placeholder="数值越大排序越靠前" />
      </el-form-item>
      <el-form-item label="热度评分" prop="popularityScore">
        <el-input v-model="formData.popularityScore" placeholder="用于推荐排序" />
      </el-form-item>
      <!-- <el-form-item label="创建时间" prop="createdAt">
        <el-date-picker v-model="formData.createdAt" type="date" value-format="x" placeholder="选择创建时间" />
      </el-form-item>
      <el-form-item label="更新时间" prop="updatedAt">
        <el-date-picker v-model="formData.updatedAt" type="date" value-format="x" placeholder="选择更新时间" />
      </el-form-item> -->
      <el-form-item label="开场白" prop="prologue">
        <el-input v-model="formData.prologue" placeholder="请输入开场白" />
      </el-form-item>
      <el-form-item label="开场白音频" prop="prologueAudio">
        <el-input v-model="formData.prologueAudio" placeholder="请输入开场白音频URL" />
      </el-form-item>
      <el-form-item label="音频Id" prop="voiceId">
        <el-input v-model="formData.voiceId" placeholder="请输入音频Id" />
      </el-form-item>
    </el-form>
    <template #footer>
      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
      <el-button @click="dialogVisible = false">取 消</el-button>
    </template>
  </Dialog>
</template>
<script setup lang="ts">
import { AiCompanionApi, AiCompanion } from '@/api/keyboard/aicompanion'
import { CropperImage } from '@/components/Cropper'
import * as FileApi from '@/api/infra/file'
import type { Cropper } from 'cropperjs'

/** AI陪聊角色表，用于定义恋爱/陪伴型虚拟角色的基础信息与人设 表单 */
defineOptions({ name: 'AiCompanionForm' })

const { t } = useI18n() // 国际化
const message = useMessage() // 消息弹窗

const dialogVisible = ref(false) // 弹窗的是否展示
const dialogTitle = ref('') // 弹窗的标题
const formLoading = ref(false) // 表单的加载中：1）修改时的数据加载；2）提交的按钮禁用
const formType = ref('') // 表单的类型：create - 新增；update - 修改
const formData = ref({
  id: undefined,
  avatarUrl: undefined,
  coverImageUrl: undefined,
  gender: undefined,
  ageRange: undefined,
  personalityTags: undefined,
  speakingStyle: undefined,
  systemPrompt: undefined,
  status: undefined,
  visibility: undefined,
  sortOrder: undefined,
  popularityScore: undefined,
  createdAt: undefined,
  updatedAt: undefined,
  prologue: undefined,
  prologueAudio: undefined,
  voiceId: undefined
})
const formRules = reactive({
  systemPrompt: [{ required: true, message: '系统Prompt不能为空', trigger: 'blur' }],
  status: [{ required: true, message: '状态不能为空', trigger: 'blur' }],
  visibility: [{ required: true, message: '可见性不能为空', trigger: 'blur' }],
  // createdAt: [{ required: true, message: '创建时间不能为空', trigger: 'blur' }],
  // updatedAt: [{ required: true, message: '更新时间不能为空', trigger: 'blur' }]
})
const formRef = ref() // 表单 Ref

/** 头像上传 */
const avatarInputRef = ref<HTMLInputElement>()
const cropperVisible = ref(false)
const avatarCropSrc = ref('')
const avatarPreview = ref('')
const avatarUploading = ref(false)
let cropperInstance: Cropper | null = null

/** 封面图上传 */
const coverInputRef = ref<HTMLInputElement>()
const coverUploading = ref(false)

const onAvatarFileChange = (e: Event) => {
  const file = (e.target as HTMLInputElement).files?.[0]
  if (!file) return
  const reader = new FileReader()
  reader.onload = (ev) => {
    avatarCropSrc.value = (ev.target?.result as string) ?? ''
    avatarPreview.value = ''
    cropperVisible.value = true
  }
  reader.readAsDataURL(file)
    // 清空 input 以便重复选择同一文件
    ; (e.target as HTMLInputElement).value = ''
}

const onCropperReady = (cropper: Cropper) => {
  cropperInstance = cropper
}

const onCropend = ({ imgBase64 }: { imgBase64: string }) => {
  avatarPreview.value = imgBase64
}

const confirmCropAvatar = async () => {
  if (!cropperInstance) return
  const canvas = cropperInstance.getCroppedCanvas({ width: 200, height: 200 })
  canvas.toBlob(async (blob) => {
    if (!blob) return
    avatarUploading.value = true
    try {
      const file = new File([blob], 'avatar.png', { type: 'image/png' })
      const res = await FileApi.updateFile({ file, directory: 'ai_companion_avatar' })
      formData.value.avatarUrl = res.data
      cropperVisible.value = false
      message.success('头像上传成功')
    } finally {
      avatarUploading.value = false
    }
  }, 'image/png')
}

const onCoverFileChange = async (e: Event) => {
  const file = (e.target as HTMLInputElement).files?.[0]
  if (!file) return
  coverUploading.value = true
  try {
    const res = await FileApi.updateFile({ file, directory: 'ai_companion_cover' })
    formData.value.coverImageUrl = res.data
    message.success('封面图上传成功')
  } finally {
    coverUploading.value = false
      // 清空 input 以便重复选择同一文件
      ; (e.target as HTMLInputElement).value = ''
  }
}

/** 打开弹窗 */
const open = async (type: string, id?: number) => {
  dialogVisible.value = true
  dialogTitle.value = t('action.' + type)
  formType.value = type
  resetForm()
  // 修改时，设置数据
  if (id) {
    formLoading.value = true
    try {
      formData.value = await AiCompanionApi.getAiCompanion(id)
    } finally {
      formLoading.value = false
    }
  }
}
defineExpose({ open }) // 提供 open 方法，用于打开弹窗

/** 提交表单 */
const emit = defineEmits(['success']) // 定义 success 事件，用于操作成功后的回调
const submitForm = async () => {
  // 校验表单
  await formRef.value.validate()
  // 提交请求
  formLoading.value = true
  try {
    const data = formData.value as unknown as AiCompanion
    if (formType.value === 'create') {
      await AiCompanionApi.createAiCompanion(data)
      message.success(t('common.createSuccess'))
    } else {
      await AiCompanionApi.updateAiCompanion(data)
      message.success(t('common.updateSuccess'))
    }
    dialogVisible.value = false
    // 发送操作成功的事件
    emit('success')
  } finally {
    formLoading.value = false
  }
}

/** 重置表单 */
const resetForm = () => {
  formData.value = {
    id: undefined,
    avatarUrl: undefined,
    coverImageUrl: undefined,
    gender: undefined,
    ageRange: undefined,
    personalityTags: undefined,
    speakingStyle: undefined,
    systemPrompt: undefined,
    status: undefined,
    visibility: undefined,
    sortOrder: undefined,
    popularityScore: undefined,
    createdAt: undefined,
    updatedAt: undefined,
    prologue: undefined,
    prologueAudio: undefined,
    voiceId: undefined
  }
  formRef.value?.resetFields()
}
</script>

<style scoped>
.cover-image-preview {
  width: 100px;
  height: 60px;
  border-radius: 4px;
  cursor: pointer;
}

/* 表单布局优化 */
.el-form-item {
  margin-bottom: 16px;
}

/* 按钮间距 */
.el-button {
  margin-right: 8px;
}
</style>