<template>
  <div class="creating-page">
    <!-- 飘浮装饰元素 -->
    <div class="floating-deco d1">☁️</div>
    <div class="floating-deco d2">🌟</div>
    <div class="floating-deco d3">🎨</div>
    <div class="floating-deco d4">📖</div>
    <div class="floating-deco d5">✨</div>

    <!-- 进度环 -->
    <div class="ring-wrap">
      <svg width="180" height="180" class="ring-svg">
        <circle cx="90" cy="90" r="80" fill="none" stroke="rgba(255,255,255,0.5)" stroke-width="8" />
        <circle cx="90" cy="90" r="80" fill="none" stroke="var(--primary)" stroke-width="8"
          :stroke-dasharray="502" :stroke-dashoffset="502 - (502 * progress / 100)"
          stroke-linecap="round" class="ring-fill" />
      </svg>
      <div class="ring-center">
        <div class="ring-pct">{{ progress }}%</div>
        <div class="ring-label">创作进度</div>
      </div>
      <!-- 星星点缀 -->
      <div class="ring-stars">
        <span class="ring-star s1">✨</span>
        <span class="ring-star s2">⭐</span>
        <span class="ring-star s3">✨</span>
        <span class="ring-star s4">⭐</span>
      </div>
    </div>

    <!-- 状态文字 -->
    <div class="stage-text">{{ stage }}</div>

    <!-- 轮转创作 tips -->
    <div v-if="!error" class="rotating-tips">
      <Transition name="tip-fade" mode="out-in">
        <div class="rotating-tip" :key="currentTipIdx">{{ creatingTips[currentTipIdx] }}</div>
      </Transition>
    </div>

    <!-- 网络波动提示（非致命，轮询仍在继续） -->
    <div v-if="networkWarn && !error" class="network-warn">
      网络不太稳定，正在尝试重新连接{{ dots }}
    </div>

    <!-- 错误重试 -->
    <div v-if="error" class="error-box">
      <div class="error-emoji">😔</div>
      <div class="error-text">{{ error }}</div>
      <button v-if="store.workId" class="btn-primary error-retry-btn" @click="resumePolling">恢复查询进度</button>
      <button class="btn-primary error-retry-btn" :class="{ 'btn-outline': store.workId }" @click="retry">重新创作</button>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import { useRouter } from 'vue-router'
import { Client } from '@stomp/stompjs'
import { store } from '@/utils/store'
import { createStory, getWorkDetail } from '@/api'
import { STATUS, getRouteByStatus } from '@/utils/status'
import config from '@/utils/config'
import bridge from '@/utils/bridge'

const router = useRouter()
const progress = ref(0)
const stage = ref('准备中...')
const dots = ref('')
const error = ref('')
const networkWarn = ref(false)
const currentTipIdx = ref(0)
const creatingTips = [
  'AI 画师正在构思精彩故事...',
  '魔法画笔正在绘制插画...',
  '故事世界正在成形...',
  '角色们正在准备登场...',
  '色彩魔法正在施展中...',
]

let pollTimer = null
let dotTimer = null
let tipTimer = null
let stompClient = null
let wsDegraded = false  // WebSocket 已降级到轮询，防止重复降级
let submitted = false
let consecutiveErrors = 0
const MAX_SILENT_ERRORS = 3
const MAX_POLL_ERRORS = 15

// 错误消息脱敏
function sanitizeError(msg) {
  if (!msg) return '创作遇到问题，请重新尝试'
  if (msg.includes('400') || msg.includes('status code')) return '创作请求异常，请返回重新操作'
  if (msg.includes('火山引擎') || msg.includes('VolcEngine')) return 'AI 服务暂时繁忙，请稍后重试'
  if (msg.includes('额度')) return msg // 额度提示保留原文
  if (msg.includes('重复') || msg.includes('DUPLICATE')) return '您有正在创作的作品，请等待完成'
  if (msg.includes('timeout') || msg.includes('超时')) return '创作超时，请重新尝试'
  if (msg.includes('OSS') || msg.includes('MiniMax')) return '服务暂时不可用，请稍后重试'
  if (msg.length > 50) return '创作遇到问题，请重新尝试'
  return msg
}

// 将运维级消息转为用户友好消息（隐藏分组/模型/耗时等内部细节）
function friendlyStage(pct, msg) {
  if (!msg) return '创作中...'
  // 按关键词匹配，优先级从高到低
  if (msg.includes('创作完成')) return '🎉 绘本创作完成！'
  if (msg.includes('绘图完成') || msg.includes('绘制完成')) return '🎨 插画绘制完成'
  if (msg.includes('第') && msg.includes('组')) return '🎨 正在绘制插画...'
  if (msg.includes('绘图') || msg.includes('绘制') || msg.includes('插画')) return '🎨 正在绘制插画...'
  if (msg.includes('补生成')) return '🎨 正在绘制插画...'
  if (msg.includes('语音合成') || msg.includes('配音')) return '🔊 正在合成语音...'
  if (msg.includes('故事') && msg.includes('完成')) return '📝 故事编写完成，开始绘图...'
  if (msg.includes('故事') || msg.includes('创���故事')) return '📝 正在编写故事...'
  if (msg.includes('适配') || msg.includes('角色')) return '🎨 正在准备绘图...'
  if (msg.includes('重试')) return '✨ 遇到小问题，正在重新创作...'
  if (msg.includes('失败')) return '⏳ 处理中，请稍候...'
  // 兜底：根据进度百分比返回友好��示，不展示原始技术消息
  if (pct < 20) return '✨ 正在提交创作...'
  if (pct < 50) return '📝 正在编写故事...'
  if (pct < 80) return '🎨 正在绘制插画...'
  if (pct < 100) return '🔊 即将完成...'
  return '🎉 绘本创作完成！'
}

// 持久化 workId 到 localStorage，页面刷新后可恢复轮询
function saveWorkId(id) {
  store.workId = id
  if (id) {
    localStorage.setItem('le_workId', id)
  } else {
    localStorage.removeItem('le_workId')
  }
}

function restoreWorkId() {
  if (!store.workId) {
    store.workId = localStorage.getItem('le_workId') || ''
  }
}

// ─── WebSocket 实时推送 (首次进入使用) ───
const startWebSocket = (workId) => {
  wsDegraded = false
  const wsBase = config.wsBaseUrl
    ? config.wsBaseUrl
    : `${location.protocol === 'https:' ? 'wss' : 'ws'}://${location.host}`
  const wsUrl = `${wsBase}/ws/websocket?orgId=${encodeURIComponent(store.orgId)}`

  stompClient = new Client({
    brokerURL: wsUrl,
    reconnectDelay: 0, // 不自动重连，失败直接降级轮询
    onConnect: () => {
      stompClient.subscribe(`/topic/progress/${workId}`, (msg) => {
        try {
          const data = JSON.parse(msg.body)
          if (data.progress != null && data.progress > progress.value) progress.value = data.progress
          if (data.message) stage.value = friendlyStage(data.progress, data.message)

          if (data.progress >= 100) {
            progress.value = 100
            stage.value = '🎉 绘本创作完成！'
            closeWebSocket()
            saveWorkId('')
            bridge.send('WORK_COMPLETED', { workId })
            const route = getRouteByStatus(STATUS.COMPLETED, workId)
            if (route) setTimeout(() => router.replace(route), 800)
          } else if (data.progress < 0) {
            closeWebSocket()
            saveWorkId('')
            bridge.send('CREATION_ERROR', { message: sanitizeError(data.message) })
            error.value = sanitizeError(data.message)
          }
        } catch { /* ignore parse error */ }
      })
    },
    onStompError: () => {
      if (wsDegraded) return
      wsDegraded = true
      closeWebSocket()
      startPolling(workId)
    },
    onWebSocketError: () => {
      if (wsDegraded) return
      wsDegraded = true
      closeWebSocket()
      startPolling(workId)
    },
    onWebSocketClose: () => {
      if (wsDegraded) return
      if (store.workId) {
        wsDegraded = true
        closeWebSocket()
        startPolling(workId)
      }
    }
  })
  stompClient.activate()
}

const closeWebSocket = () => {
  if (stompClient) {
    try { stompClient.deactivate() } catch { /* ignore */ }
    stompClient = null
  }
}

// ─── B2 轮询 (重进 / WebSocket 降级使用) ───
const startPolling = (workId) => {
  if (pollTimer) clearInterval(pollTimer)
  consecutiveErrors = 0
  networkWarn.value = false

  pollTimer = setInterval(async () => {
    try {
      const detail = await getWorkDetail(workId)
      const work = detail.data
      if (!work) return

      // 轮询成功，清除网络异常状态
      if (consecutiveErrors > 0 || networkWarn.value) {
        consecutiveErrors = 0
        networkWarn.value = false
      }

      if (work.progress != null && work.progress > progress.value) progress.value = work.progress
      if (work.progressMessage) stage.value = friendlyStage(progress.value, work.progressMessage)

      // 状态 >= COMPLETED(3) 表示创作已结束，根据具体状态导航
      if (work.status >= STATUS.COMPLETED) {
        progress.value = 100
        stage.value = '🎉 绘本创作完成！'
        clearInterval(pollTimer)
        pollTimer = null
        saveWorkId('')
        bridge.send('WORK_COMPLETED', { workId })
        const route = getRouteByStatus(work.status, workId)
        if (route) setTimeout(() => router.replace(route), 800)
      } else if (work.status === STATUS.FAILED) {
        clearInterval(pollTimer)
        pollTimer = null
        saveWorkId('')
        bridge.send('CREATION_ERROR', { message: sanitizeError(work.failReason) })
        error.value = sanitizeError(work.failReason)
      }
    } catch {
      consecutiveErrors++
      if (consecutiveErrors > MAX_POLL_ERRORS) {
        // 连续失败太多次，暂停轮询，让用户手动恢复
        clearInterval(pollTimer)
        pollTimer = null
        networkWarn.value = false
        error.value = '网络连接异常，创作仍在后台进行中'
      } else if (consecutiveErrors > MAX_SILENT_ERRORS) {
        // 连续失败超过阈值，提示网络波动但继续轮询
        networkWarn.value = true
      }
      // 前几次静默忽略，避免偶尔的网络抖动触发提示
    }
  }, 8000)
}

const startCreation = async () => {
  if (submitted) return  // 防重复
  submitted = true

  error.value = ''
  progress.value = 5
  stage.value = '📝 正在提交创作请求...'

  try {
    const res = await createStory({
      imageUrl: store.imageUrl,
      storyHint: store.storyData?.storyHint || '',
      style: store.selectedStyle,
      title: store.storyData?.title || '',
      author: store.storyData?.author,
      heroCharId: store.selectedCharacter?.charId,
      extractId: store.extractId,
    })

    const workId = res.data?.workId
    if (!workId) {
      error.value = res.msg || '创作提交失败'
      submitted = false
      return
    }

    saveWorkId(workId)
    bridge.send('WORK_CREATED', { workId })
    progress.value = 10
    stage.value = '📝 故事构思中...'
    // 首次提交：优先 WebSocket 实时推送
    startWebSocket(workId)

  } catch (e) {
    // 创作提交可能已入库（超时但服务端已接收）
    if (store.workId) {
      progress.value = 10
      stage.value = '📝 创作已提交到后台...'
      startPolling(store.workId)
    } else {
      bridge.send('CREATION_ERROR', { message: sanitizeError(e.message) })
      error.value = sanitizeError(e.message)
      submitted = false
    }
  }
}

const resumePolling = () => {
  error.value = ''
  networkWarn.value = false
  progress.value = 10
  stage.value = '📝 正在查询创作进度...'
  startPolling(store.workId)
}

const retry = () => {
  saveWorkId('')
  submitted = false
  startCreation()
}

onMounted(() => {
  dotTimer = setInterval(() => {
    dots.value = dots.value.length >= 3 ? '' : dots.value + '.'
  }, 500)

  tipTimer = setInterval(() => {
    currentTipIdx.value = (currentTipIdx.value + 1) % creatingTips.length
  }, 3500)

  // 恢复 workId：优先从URL参数（作品列表跳入），其次从localStorage（页面刷新）
  const urlWorkId = new URLSearchParams(window.location.search).get('workId')
  if (urlWorkId) {
    saveWorkId(urlWorkId)
  } else {
    restoreWorkId()
  }

  // 如果已有进行中的任务，恢复轮询而非重新提交
  if (store.workId) {
    submitted = true
    progress.value = 10
    stage.value = '📝 正在查询创作进度...'
    startPolling(store.workId)
  } else {
    startCreation()
  }
})

onUnmounted(() => {
  closeWebSocket()
  if (pollTimer) clearInterval(pollTimer)
  if (dotTimer) clearInterval(dotTimer)
  if (tipTimer) clearInterval(tipTimer)
})
</script>

<style lang="scss" scoped>
.creating-page {
  min-height: 100vh;
  background: linear-gradient(160deg, #FFF8E1 0%, #FFF0F0 40%, #F0F8FF 100%);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 24px;
  position: relative;
  overflow: hidden;
}

/* 飘浮装饰元素 */
.floating-deco {
  position: absolute;
  font-size: 28px;
  opacity: 0.35;
  pointer-events: none;
  animation: floatDeco 6s ease-in-out infinite;
}
.d1 { top: 8%; left: 10%; animation-delay: 0s; font-size: 36px; }
.d2 { top: 15%; right: 12%; animation-delay: 1.2s; font-size: 24px; }
.d3 { bottom: 20%; left: 8%; animation-delay: 2.4s; }
.d4 { bottom: 12%; right: 15%; animation-delay: 0.8s; font-size: 32px; }
.d5 { top: 40%; right: 6%; animation-delay: 3.6s; font-size: 20px; }
@keyframes floatDeco {
  0%, 100% { transform: translateY(0) rotate(0deg); }
  25% { transform: translateY(-12px) rotate(5deg); }
  50% { transform: translateY(-6px) rotate(-3deg); }
  75% { transform: translateY(-16px) rotate(3deg); }
}

.ring-wrap {
  position: relative;
  width: 180px;
  height: 180px;
  margin-bottom: 32px;
}
.ring-svg { transform: rotate(-90deg); }
.ring-fill { transition: stroke-dashoffset 0.8s ease; }
.ring-center {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}
.ring-pct { font-size: 36px; font-weight: 900; color: var(--primary); }
.ring-label { font-size: 12px; color: var(--text-sub); }

/* 星星点缀在进度环外圈 */
.ring-stars {
  position: absolute;
  inset: -12px;
  pointer-events: none;
}
.ring-star {
  position: absolute;
  font-size: 14px;
  animation: starTwinkle 2s ease-in-out infinite;
}
.ring-star.s1 { top: -4px; left: 50%; transform: translateX(-50%); animation-delay: 0s; }
.ring-star.s2 { bottom: -4px; left: 50%; transform: translateX(-50%); animation-delay: 0.5s; }
.ring-star.s3 { left: -4px; top: 50%; transform: translateY(-50%); animation-delay: 1s; }
.ring-star.s4 { right: -4px; top: 50%; transform: translateY(-50%); animation-delay: 1.5s; }
@keyframes starTwinkle {
  0%, 100% { opacity: 0.3; transform: scale(0.8); }
  50% { opacity: 1; transform: scale(1.2); }
}

.stage-text { font-size: 18px; font-weight: 700; text-align: center; }

/* 轮转 tips */
.rotating-tips {
  margin-top: 14px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.rotating-tip {
  font-size: 14px;
  color: #B0876E;
  font-weight: 500;
  text-align: center;
  letter-spacing: 0.3px;
}
.tip-fade-enter-active,
.tip-fade-leave-active {
  transition: opacity 0.5s ease, transform 0.5s ease;
}
.tip-fade-enter-from {
  opacity: 0;
  transform: translateY(8px);
}
.tip-fade-leave-to {
  opacity: 0;
  transform: translateY(-8px);
}

.network-warn {
  margin-top: 12px;
  font-size: 13px;
  color: #F59E0B;
  text-align: center;
}

.error-box {
  margin-top: 24px;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}
.error-emoji { font-size: 40px; margin-bottom: 12px; }
.error-text { color: #EF4444; font-size: 14px; font-weight: 600; line-height: 1.6; max-width: 260px; }
.error-retry-btn { max-width: 200px; margin-top: 16px; }
.error-retry-btn.btn-outline {
  background: transparent;
  color: var(--text-sub);
  border: 1px solid var(--border);
  font-size: 13px;
}
</style>
