<template>
  <div class="upload-page page-fullscreen">
    <PageHeader title="上传作品" subtitle="拍下孩子的画，让AI识别角色" :step="0" />

    <div class="content page-content">
      <template v-if="!preview">
        <!-- 上传区域 -->
        <div class="upload-area card">
          <template v-if="uploading">
            <div class="uploading-icon">📤</div>
            <div class="uploading-text">正在上传...</div>
            <div class="progress-bar"><div class="progress-fill" /></div>
          </template>
          <template v-else>
            <div class="upload-icon">🖼️</div>
            <div class="upload-title">上传孩子的画作</div>
            <div class="upload-desc">支持拍照或从相册选择<br/>AI会自动识别画中的角色</div>
          </template>
        </div>

        <!-- 拍照/相册按钮 -->
        <div class="action-btns">
          <div class="action-btn camera" @click="pickImage('camera')">
            <div class="action-emoji">📷</div>
            <div class="action-label">拍照</div>
            <input ref="cameraInput" type="file" accept="image/*" capture="environment" @change="onFileChange" style="display:none" />
          </div>
          <div class="action-btn album" @click="pickImage('album')">
            <div class="action-emoji">🖼️</div>
            <div class="action-label">相册</div>
            <input ref="albumInput" type="file" accept="image/*" @change="onFileChange" style="display:none" />
          </div>
        </div>
      </template>

      <template v-else>
        <!-- 预览 -->
        <div class="preview-card card">
          <div class="preview-image">
            <img :src="preview" alt="预览" />
          </div>
          <!-- 识别中：填满空间 -->
          <div v-if="uploading" class="recognizing-box">
            <div class="recognizing-emojis">
              <span class="recognizing-emoji e1">🎨</span>
              <span class="recognizing-emoji e2">✏️</span>
              <span class="recognizing-emoji e3">🖌️</span>
            </div>
            <div class="recognizing-text">{{ uploadProgress || 'AI 小画家正在认识你的角色...' }}</div>
          </div>
          <div v-else class="preview-info">
            <div class="preview-ok">✅ 已选择图片</div>
          </div>
        </div>

        <!-- 识别中的趣味等待内容（填满空白） -->
        <div v-if="uploading" class="waiting-content">
          <div class="waiting-card">
            <div class="waiting-title">✨ AI 正在为你做这些事</div>
            <div class="waiting-steps">
              <div class="w-step" :class="{ active: uploadStage >= 1 }">
                <span class="w-icon">📤</span>
                <span>上传画作到云端</span>
                <span v-if="uploadStage >= 1" class="w-done">✓</span>
              </div>
              <div class="w-step" :class="{ active: uploadStage >= 2 }">
                <span class="w-icon">👀</span>
                <span>AI 识别画中角色</span>
                <span v-if="uploadStage >= 2" class="w-done">✓</span>
              </div>
              <div class="w-step" :class="{ active: uploadStage >= 3 }">
                <span class="w-icon">🎭</span>
                <span>提取角色特征</span>
              </div>
            </div>
          </div>
          <div class="waiting-funfact">
            <span class="ff-icon">💡</span>
            <span class="ff-text">你知道吗？AI 画师可以识别超过 100 种不同的卡通角色哦！</span>
          </div>
        </div>

        <div v-if="!quotaOk" class="quota-warn">{{ quotaMsg }}</div>
        <div v-if="uploadError" class="upload-error">{{ uploadError }}</div>
        <div class="preview-actions">
          <button class="btn-ghost" @click="reset">重新上传</button>
          <button class="btn-primary" :disabled="uploading" @click="goNext">
            {{ uploading ? 'AI 识别中...' : '识别角色 →' }}
          </button>
        </div>
      </template>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import PageHeader from '@/components/PageHeader.vue'
import { store } from '@/utils/store'
import { extractCharacters, ossUpload, checkQuota } from '@/api'

const router = useRouter()
const preview = ref(null)
const uploading = ref(false)
const cameraInput = ref(null)
const albumInput = ref(null)
const fileSizeInfo = ref('')
const compressed = ref(false)
const saveOriginal = ref(false)
const uploadProgress = ref('')
const uploadStage = ref(0) // 0=未开始 1=上传中 2=识别中 3=提取中
const quotaOk = ref(true)
const quotaMsg = ref('')
let selectedFile = null

// 进入页面时检查额度
onMounted(async () => {
  try {
    await checkQuota()
    quotaOk.value = true
  } catch (e) {
    const msg = e.message || ''
    // 只有明确的额度不足才阻止，网络/签名错误放行（后端会二次校验）
    if (msg.includes('额度') || msg.includes('QUOTA') || msg.includes('30003')) {
      quotaOk.value = false
      quotaMsg.value = '创作额度不足，请联系管理员'
    }
    // 其他错误（403签名/网络超时等）静默放行
  }
})

const pickImage = (type) => {
  if (type === 'camera') cameraInput.value?.click()
  else albumInput.value?.click()
}

/**
 * Canvas 压缩：将超高清图片缩放到 maxWidth，输出 JPEG 质量 quality
 * 目标：手机原片 8-20MB → 压缩后 <2MB
 */
const MAX_WIDTH = 1920
const MAX_SIZE = 2 * 1024 * 1024 // 2MB
const JPEG_QUALITY = 0.85

function compressImage(file) {
  return new Promise((resolve) => {
    // 小于 2MB 的图片不压缩
    if (file.size <= MAX_SIZE) {
      resolve(file)
      return
    }

    const img = new Image()
    const url = URL.createObjectURL(file)
    img.onload = () => {
      URL.revokeObjectURL(url)

      let { width, height } = img
      // 缩放到 maxWidth
      if (width > MAX_WIDTH) {
        height = Math.round(height * MAX_WIDTH / width)
        width = MAX_WIDTH
      }

      const canvas = document.createElement('canvas')
      canvas.width = width
      canvas.height = height
      const ctx = canvas.getContext('2d')
      ctx.drawImage(img, 0, 0, width, height)

      canvas.toBlob(
        (blob) => {
          if (blob) {
            const compressedFile = new File([blob], file.name.replace(/\.\w+$/, '.jpg'), {
              type: 'image/jpeg',
              lastModified: Date.now()
            })
            resolve(compressedFile)
          } else {
            resolve(file) // fallback to original
          }
        },
        'image/jpeg',
        JPEG_QUALITY
      )
    }
    img.onerror = () => {
      URL.revokeObjectURL(url)
      resolve(file) // fallback
    }
    img.src = url
  })
}

function formatSize(bytes) {
  if (bytes < 1024) return bytes + ' B'
  if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(0) + ' KB'
  return (bytes / (1024 * 1024)).toFixed(1) + ' MB'
}

const onFileChange = async (e) => {
  const file = e.target.files?.[0]
  if (!file) return
  uploading.value = true
  compressed.value = false

  const originalSize = file.size

  // 压缩超大图片
  const processedFile = await compressImage(file)
  selectedFile = processedFile

  if (processedFile.size < originalSize) {
    compressed.value = true
    fileSizeInfo.value = `${formatSize(originalSize)} → ${formatSize(processedFile.size)}`
  } else {
    fileSizeInfo.value = formatSize(originalSize)
  }

  // 本地预览（用压缩后的文件）
  const reader = new FileReader()
  reader.onload = (ev) => {
    preview.value = ev.target.result
    uploading.value = false
  }
  reader.readAsDataURL(processedFile)
}

const reset = () => {
  preview.value = null
  selectedFile = null
  fileSizeInfo.value = ''
  compressed.value = false
  uploadError.value = ''
}

const uploadError = ref('')

// 错误消息脱敏：不向用户暴露后端服务名称
function sanitizeError(msg) {
  if (!msg) return '请稍后重试'
  if (msg.includes('火山引擎') || msg.includes('VolcEngine')) return '图片分析服务暂时不可用，请稍后重试'
  if (msg.includes('MiniMax')) return '语音服务暂时不可用，请稍后重试'
  if (msg.includes('OSS') || msg.includes('oss')) return '文件存储服务异常，请稍后重试'
  if (msg.includes('401') || msg.includes('签名')) return '请返回首页重新开始'
  if (msg.includes('403')) return '认证失败，请检查机构配置后重试'
  if (msg.includes('timeout') || msg.includes('超时')) return '网络超时，请检查网络后重试'
  return msg
}

const goNext = async () => {
  if (!selectedFile) return
  if (!quotaOk.value) {
    uploadError.value = quotaMsg.value || '创作额度不足'
    return
  }
  uploading.value = true
  uploadError.value = ''
  uploadStage.value = 1
  try {
    // Step 1: STS 直传图片到 OSS
    uploadProgress.value = '上传画作到云端...'
    const ossUrl = await ossUpload(selectedFile, {
      type: 'img',
      onProgress: (p) => { uploadProgress.value = `上传画作 ${p}%` }
    })
    uploadStage.value = 2

    // Step 2: 用 URL 调 A6 角色提取
    uploadProgress.value = 'AI 正在识别角色...'
    const res = await extractCharacters(ossUrl, {
      saveOriginal: saveOriginal.value
    })
    const data = res.data || {}
    const chars = (data.characters || []).map(c => ({
      ...c,
      type: c.charType || c.type || 'SIDEKICK'
    }))
    if (chars.length === 0) throw new Error('AI未识别到角色，请更换图片重试')
    store.extractId = data.extractId || ''
    store.characters = chars
    store.imageUrl = ossUrl
    if (data.workId) store.originalWorkId = data.workId
    router.push('/characters')
  } catch (e) {
    uploadError.value = '识别失败：' + sanitizeError(e.message)
    uploading.value = false
    uploadProgress.value = ''
  }
}
</script>

<style lang="scss" scoped>
.upload-page {
  min-height: 100vh;
  background: var(--bg);
  display: flex;
  flex-direction: column;
}
.content {
  flex: 1;
  padding: 16px 20px;
  display: flex;
  flex-direction: column;
}
.upload-area {
  flex: 1;
  min-height: 280px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  border: 3px dashed var(--border);
  text-align: center;
  padding: 32px;
}
.upload-icon, .uploading-icon {
  font-size: 64px;
}
.uploading-icon { animation: pulse 1.5s infinite; }
.upload-title { font-size: 18px; font-weight: 700; margin-top: 16px; }
.upload-desc { font-size: 14px; color: var(--text-sub); margin-top: 8px; line-height: 1.6; }
.uploading-text { font-size: 16px; font-weight: 600; margin-top: 16px; }
.progress-bar {
  width: 200px; height: 6px; background: var(--border); border-radius: 3px; margin-top: 16px; overflow: hidden;
}
.progress-fill {
  width: 100%; height: 100%; background: var(--gradient); border-radius: 3px;
  animation: loading 1.5s ease-in-out infinite;
}
@keyframes loading { 0%{transform:translateX(-100%)} 100%{transform:translateX(200%)} }

.action-btns {
  display: flex;
  gap: 12px;
  margin-top: 20px;
}
.action-btn {
  flex: 1;
  border-radius: var(--radius);
  padding: 20px 0;
  text-align: center;
  cursor: pointer;
  box-shadow: var(--shadow);

  &.camera { background: var(--gradient); }
  &.album { background: var(--gradient-purple); }
}
.action-emoji { font-size: 32px; }
.action-label { font-size: 15px; font-weight: 700; color: #fff; margin-top: 8px; }

.preview-card { overflow: hidden; flex: 1; }
.preview-image {
  width: 100%;
  aspect-ratio: 4/3;
  background: #F5F0E8;
  img { width: 100%; height: 100%; object-fit: cover; }
}
.preview-info { padding: 20px; text-align: center; }
.preview-ok { font-size: 15px; font-weight: 600; color: var(--success); }

/* 儿童风格识别中动画 */
.recognizing-box {
  background: linear-gradient(135deg, #FFF8E1, #FFFDE7);
  border-radius: 0 0 16px 16px;
  padding: 20px 16px;
  text-align: center;
}
.recognizing-emojis {
  display: flex;
  justify-content: center;
  gap: 12px;
  margin-bottom: 12px;
  padding: 8px 0;
}
.recognizing-emoji {
  font-size: 28px;
  display: inline-block;
  animation: emojiPop 1.8s ease-in-out infinite;
}
.recognizing-emoji.e1 { animation-delay: 0s; }
.recognizing-emoji.e2 { animation-delay: 0.4s; }
.recognizing-emoji.e3 { animation-delay: 0.8s; }
@keyframes emojiPop {
  0%, 100% { transform: scale(1) rotate(0deg); opacity: 0.5; }
  50% { transform: scale(1.3) rotate(10deg); opacity: 1; }
}
.recognizing-text {
  font-size: 15px;
  font-weight: 700;
  color: #F59E0B;
  letter-spacing: 0.5px;
}

// 等待内容 — 填满空白
.waiting-content {
  display: flex; flex-direction: column; gap: 12px; flex: 1;
}
.waiting-card {
  background: rgba(255,255,255,0.92); border-radius: 20px;
  padding: 18px 20px; box-shadow: 0 4px 16px rgba(0,0,0,0.05);
}
.waiting-title {
  font-size: 15px; font-weight: 800; color: #1E293B; margin-bottom: 14px;
}
.waiting-steps { display: flex; flex-direction: column; gap: 10px; }
.w-step {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 14px; border-radius: 14px; background: #F8F8F5;
  font-size: 14px; color: #94A3B8; transition: all 0.3s;
  &.active { background: #FFF8E7; color: #1E293B; font-weight: 600; }
}
.w-icon { font-size: 20px; }
.w-done { margin-left: auto; color: #10B981; font-weight: 700; font-size: 16px; }

.waiting-funfact {
  display: flex; align-items: flex-start; gap: 10px;
  background: linear-gradient(135deg, #EDE9FE, #F5F3FF);
  border-radius: 16px; padding: 14px 16px;
}
.ff-icon { font-size: 20px; flex-shrink: 0; }
.ff-text { font-size: 13px; color: #6D28D9; line-height: 1.6; }
.quota-warn {
  background: #FEF3C7; color: #92400E; font-size: 13px; text-align: center;
  padding: 10px 16px; border-radius: 10px; margin-top: 12px; font-weight: 600;
}
.upload-error { color: #EF4444; font-size: 13px; text-align: center; margin-top: 12px; font-weight: 500; }
.preview-actions { display: flex; gap: 12px; margin-top: 12px; button { flex: 1; } }
</style>
