<script setup lang="ts">
import { computed, onBeforeUnmount, onMounted, ref } from 'vue'
import QRCode from 'qrcode'
import { ElMessageBox } from 'element-plus'
import {
  CircleCheck,
  CircleClose,
  Clock,
  Loading,
  RefreshRight,
  Warning,
} from '@element-plus/icons-vue'

import { showError, showSuccess } from '@/lib/feedback'
import {
  confirmKuaishouCloudClaimRole,
  fetchClaimDetail,
  redeemKuaishouCloudClaim,
  verifyKuaishouCloudClaimTicket,
} from '@/services/claim'
import type { ClaimDetailData } from '@/types/claim'

const props = defineProps<{
  token: string
}>()

const loading = ref(true)
const submitting = ref(false)
const refreshingRole = ref(false)
const confirmingRole = ref(false)
const redeeming = ref(false)
const errorMessage = ref('')
const detail = ref<ClaimDetailData | null>(null)
const ticketCode = ref('')
const qrCodeDataUrl = ref('')
let pollTimer = 0

const flow = computed(() => detail.value?.kuaishouCloudFulfillment || null)
const order = computed(() => detail.value?.order || null)
const orderItem = computed(() => detail.value?.orderItem || null)
const task = computed(() => detail.value?.task || null)

const roleName = computed(() => flow.value?.role.name || flow.value?.binding.roleName || '')
const roleId = computed(() => flow.value?.role.rid || flow.value?.binding.roleId || '')
const isTicketVerified = computed(() => flow.value?.ticket.status === 'verified')
const isBindUrlExpired = computed(() => {
  const expiresAt = String(flow.value?.binding.bindExpiresAt || '').trim()
  if (!expiresAt) {
    return false
  }

  const expiresTime = Date.parse(expiresAt)
  return Number.isFinite(expiresTime) && expiresTime <= Date.now()
})
const isBindingPrepared = computed(
  () =>
    flow.value?.binding.prepareStatus === 'ready' &&
    Boolean(String(flow.value?.binding.bindUrl || '').trim()) &&
    !isBindUrlExpired.value,
)
const isBindingPreparing = computed(() => flow.value?.binding.prepareStatus === 'pending')
const canEnterBindingStep = computed(() => isTicketVerified.value)
const isRoleReady = computed(() => Boolean(roleName.value || roleId.value))
const isRoleConfirmed = computed(() => String(task.value?.status || '').trim() === 'role_confirmed')
const isDispatched = computed(() => String(flow.value?.dispatch.status || '').trim() === 'success')
const isCompleted = computed(
  () =>
    String(task.value?.status || '').trim() === 'completed' ||
    String(flow.value?.consume.status || '').trim() === 'success',
)
const hasRedeemResult = computed(() => {
  const status = String(task.value?.status || '').trim()
  return (
    isDispatched.value ||
    ['dispatched_pending_return', 'completed', 'manual_review', 'failed'].includes(status)
  )
})
const canSubmitTicket = computed(
  () =>
    !['completed', 'manual_review', 'closed', 'expired'].includes(
      String(task.value?.status || '').trim(),
    ) && !submitting.value,
)
const currentStep = computed(() => {
  if (hasRedeemResult.value) {
    return 4
  }

  if (isRoleConfirmed.value) {
    return 3
  }

  if (canEnterBindingStep.value) {
    return 2
  }

  return 1
})

const progressText = computed(() => {
  if (hasRedeemResult.value) {
    return '兑换结果已生成'
  }
  if (isRoleConfirmed.value) {
    return '角色已确认，等待兑换'
  }
  if (isTicketVerified.value) {
    return isBindingPrepared.value ? '请完成扫码绑定' : '绑定链接刷新中，请稍候'
  }
  return '等待提交核销码'
})
const resultTitle = computed(() => {
  if (isCompleted.value) {
    return '兑换成功'
  }

  if (isDispatched.value) {
    return '兑换请求已提交'
  }

  return '结果已记录'
})
const resultDescription = computed(() => {
  if (isCompleted.value) {
    return '当前兑换流程已经完成。发货、退号和核销结果会保存在后台任务界面。'
  }

  return '你的兑换请求已经提交。发货、退号和核销结果会由系统保存在后台任务界面，无需在此页面等待。'
})

async function generateQRCode(url: string) {
  if (!url) {
    qrCodeDataUrl.value = ''
    return
  }

  try {
    qrCodeDataUrl.value = await QRCode.toDataURL(url, {
      width: 280,
      margin: 2,
      color: {
        dark: '#0f172a',
        light: '#ffffff',
      },
    })
  } catch (error) {
    qrCodeDataUrl.value = ''
    console.error('生成二维码失败:', error)
  }
}

async function applyDetail(nextDetail: ClaimDetailData) {
  detail.value = nextDetail
  if (!ticketCode.value && nextDetail.kuaishouCloudFulfillment?.ticket.code) {
    ticketCode.value = nextDetail.kuaishouCloudFulfillment.ticket.code
  }
  await generateQRCode(String(nextDetail.kuaishouCloudFulfillment?.binding.bindUrl || '').trim())
}

async function loadDetail(options: { silent?: boolean } = {}) {
  if (!options.silent) {
    loading.value = true
  }

  errorMessage.value = ''

  try {
    const response = await fetchClaimDetail(props.token)
    await applyDetail(response.data)
    syncPolling()
  } catch (error) {
    errorMessage.value = error instanceof Error ? error.message : '读取领取信息失败'
    stopPolling()
  } finally {
    if (!options.silent) {
      loading.value = false
    }
  }
}

async function submitTicket() {
  const normalizedTicketCode = ticketCode.value.trim()
  if (!normalizedTicketCode) {
    showError('请输入核销码')
    return
  }

  submitting.value = true
  try {
    const response = await verifyKuaishouCloudClaimTicket(props.token, {
      ticketCode: normalizedTicketCode,
    })
    await applyDetail(response.data)
    showSuccess('核销码验证通过，系统已开始准备绑定资源')
    syncPolling()
  } catch (error) {
    showError(error instanceof Error ? error.message : '核销码验证失败')
  } finally {
    submitting.value = false
  }
}

async function refreshRole() {
  refreshingRole.value = true
  try {
    await loadDetail({ silent: true })
    if (isRoleReady.value) {
      showSuccess('角色信息已刷新')
    } else {
      showError(
        flow.value?.role.errorMessage || '暂时还没有识别到角色信息，请完成绑定后稍等片刻再试',
      )
    }
  } finally {
    refreshingRole.value = false
  }
}

async function confirmRole() {
  confirmingRole.value = true
  try {
    const response = await confirmKuaishouCloudClaimRole(props.token)
    await applyDetail(response.data)
    showSuccess('角色已确认，进入下一步')
    syncPolling()
  } catch (error) {
    showError(error instanceof Error ? error.message : '确认角色失败')
  } finally {
    confirmingRole.value = false
  }
}

async function confirmRedeem() {
  try {
    await ElMessageBox.confirm(
      '兑换后不可取消，也不可退货。请确认角色和商品信息完全正确。',
      '确认兑换',
      {
        confirmButtonText: '确认兑换',
        cancelButtonText: '取消',
        type: 'warning',
        center: true,
      },
    )
  } catch {
    return
  }

  redeeming.value = true
  try {
    const response = await redeemKuaishouCloudClaim(props.token)
    await applyDetail(response.data)
    showSuccess('兑换请求已提交')
    syncPolling()
  } catch (error) {
    showError(error instanceof Error ? error.message : '兑换失败')
  } finally {
    redeeming.value = false
  }
}

function openBindUrl(useCurrentPage = false) {
  const bindUrl = String(flow.value?.binding.bindUrl || '').trim()
  if (!bindUrl) {
    showError('绑定链接还没准备好，请稍后刷新')
    return
  }

  if (useCurrentPage) {
    window.location.assign(bindUrl)
    return
  }

  window.open(bindUrl, '_blank', 'noopener,noreferrer')
}

function stopPolling() {
  if (pollTimer) {
    window.clearInterval(pollTimer)
    pollTimer = 0
  }
}

function syncPolling() {
  const taskStatus = String(task.value?.status || '').trim()
  const shouldPoll =
    Boolean(flow.value) && !hasRedeemResult.value && !['closed', 'expired'].includes(taskStatus)

  if (!shouldPoll) {
    stopPolling()
    return
  }

  if (pollTimer) {
    return
  }

  pollTimer = window.setInterval(() => {
    void loadDetail({ silent: true })
  }, 4000)
}

function formatDateTime(value: string | null) {
  if (!value) {
    return '-'
  }

  try {
    return new Date(value).toLocaleString('zh-CN', {
      year: 'numeric',
      month: '2-digit',
      day: '2-digit',
      hour: '2-digit',
      minute: '2-digit',
      second: '2-digit',
    })
  } catch {
    return value
  }
}

onMounted(() => {
  void loadDetail()
})

onBeforeUnmount(() => {
  stopPolling()
})
</script>

<template>
  <main class="claim-page">
    <section class="header-card">
      <div class="header-copy">
        <span class="eyebrow">快手 Cloud 客户领取</span>
        <h1>{{ orderItem?.skuName || '商品领取' }}</h1>
        <p>订单号：{{ order?.platformOrderId || '-' }}</p>
      </div>
      <div v-if="!loading && !errorMessage" class="step-indicator">
        <div
          v-for="step in 4"
          :key="step"
          class="step-dot"
          :class="{ active: currentStep >= step }"
        >
          {{ step }}
        </div>
      </div>
    </section>

    <div v-if="loading" class="content-card loading-card">
      <el-icon class="large-icon spinning"><Loading /></el-icon>
      <p>正在读取当前领取进度...</p>
    </div>

    <div v-else-if="errorMessage" class="content-card error-card">
      <el-icon class="large-icon error"><CircleClose /></el-icon>
      <p>{{ errorMessage }}</p>
    </div>

    <template v-else-if="detail && flow">
      <section class="summary-card">
        <div class="summary-item">
          <span>当前进度</span>
          <strong>{{ progressText }}</strong>
        </div>
        <div class="summary-item">
          <span>当前角色</span>
          <strong>{{ roleName || '待识别' }}</strong>
        </div>
        <div class="summary-item">
          <span>角色 ID</span>
          <strong>{{ roleId || '-' }}</strong>
        </div>
      </section>

      <section v-if="currentStep === 1" class="content-card">
        <h2>第 1 步：提交核销码</h2>
        <p class="muted">
          请先从快手小店复制核销码。验证通过后，系统会自动准备 Cloud
          绑定资源，不需要再让客服手工点“准备绑定资源”。
        </p>

        <el-input
          v-model="ticketCode"
          placeholder="粘贴快手核销码"
          size="large"
          :disabled="!canSubmitTicket"
          @keyup.enter="submitTicket"
        />

        <el-button
          type="primary"
          size="large"
          :loading="submitting"
          :disabled="!canSubmitTicket"
          @click="submitTicket"
        >
          验证核销码并继续
        </el-button>

        <div class="status-banner info">
          <el-icon><Clock /></el-icon>
          <span>{{
            isBindingPreparing
              ? '绑定资源会在核销通过后自动准备。'
              : '核销完成后会自动进入扫码绑定步骤。'
          }}</span>
        </div>

        <div v-if="flow.guideImages.length > 0" class="guide-section">
          <el-collapse>
            <el-collapse-item title="查看核销码图文指引" name="guide">
              <div class="guide-grid">
                <figure
                  v-for="(imageUrl, index) in flow.guideImages"
                  :key="imageUrl"
                  class="guide-figure"
                >
                  <img :src="imageUrl" :alt="`步骤 ${index + 1}`" />
                  <figcaption>步骤 {{ index + 1 }}</figcaption>
                </figure>
              </div>
            </el-collapse-item>
          </el-collapse>
        </div>
      </section>

      <section v-else-if="currentStep === 2" class="content-card">
        <h2>第 2 步：扫码绑定角色</h2>
        <p class="muted">
          核销码已验证通过。请扫码或直接打开绑定页面，绑定你自己的游戏角色。绑定信息如果一开始不对，可以重新绑定后再点下一步。
        </p>

        <div v-if="isBindingPrepared && qrCodeDataUrl" class="qr-block">
          <img :src="qrCodeDataUrl" alt="绑定二维码" class="qr-code" />
          <div class="action-row">
            <el-button type="primary" size="large" @click="openBindUrl()">
              新窗口打开绑定页
            </el-button>
            <el-button size="large" plain @click="openBindUrl(true)"> 当前页面打开 </el-button>
          </div>
        </div>

        <div v-else class="status-banner info">
          <el-icon class="spinning"><Loading /></el-icon>
          <span>系统正在准备绑定资源，请稍后自动刷新。</span>
        </div>

        <p v-if="flow.role.errorMessage" class="muted warning-line">
          {{ flow.role.errorMessage }}
        </p>
        <p v-else class="muted warning-line">
          如果当前角色不正确，请重新打开绑定页完成重新绑定，然后刷新角色信息。
        </p>
        <p class="muted meta-line">
          最近刷新：{{ formatDateTime(flow.role.refreshedAt) }}；链接有效期：{{
            formatDateTime(flow.binding.bindExpiresAt)
          }}
        </p>
        <p v-if="flow.binding.bindProbeMessage" class="muted meta-line">
          链接检测：{{ flow.binding.bindProbeStatus || '-' }} / {{ flow.binding.bindProbeMessage }}
        </p>

        <div class="action-row">
          <el-button size="large" plain :loading="refreshingRole" @click="refreshRole">
            <el-icon><RefreshRight /></el-icon>
            刷新角色信息
          </el-button>
          <el-button
            type="primary"
            size="large"
            :loading="confirmingRole"
            :disabled="!isBindingPrepared || !isRoleReady"
            @click="confirmRole"
          >
            我已完成绑定，下一步
          </el-button>
        </div>
      </section>

      <section v-else-if="currentStep === 3" class="content-card">
        <h2>第 3 步：确认兑换信息</h2>
        <p class="muted">请再次确认角色和商品信息，确认无误后再继续兑换。</p>

        <div class="info-grid">
          <div class="info-item">
            <span>角色名称</span>
            <strong>{{ roleName || '-' }}</strong>
          </div>
          <div class="info-item">
            <span>角色 ID</span>
            <strong>{{ roleId || '-' }}</strong>
          </div>
          <div class="info-item">
            <span>商品名称</span>
            <strong>{{ orderItem?.skuName || '-' }}</strong>
          </div>
          <div class="info-item">
            <span>商品数量</span>
            <strong>{{ orderItem?.quantity || 0 }}</strong>
          </div>
        </div>

        <div class="status-banner warning">
          <el-icon><Warning /></el-icon>
          <span>兑换后不可取消，也不可退货。</span>
        </div>

        <el-button type="primary" size="large" :loading="redeeming" @click="confirmRedeem">
          确认兑换
        </el-button>
      </section>

      <section v-else class="content-card">
        <div class="result-header">
          <el-icon class="large-icon success"><CircleCheck /></el-icon>
          <div>
            <h2>{{ resultTitle }}</h2>
            <p class="muted">{{ resultDescription }}</p>
          </div>
        </div>

        <div class="info-grid">
          <div class="info-item">
            <span>结果时间</span>
            <strong>{{ formatDateTime(flow.dispatch.dispatchAt) }}</strong>
          </div>
          <div class="info-item">
            <span>商品名称</span>
            <strong>{{ orderItem?.skuName || '-' }}</strong>
          </div>
          <div class="info-item">
            <span>角色名称</span>
            <strong>{{ roleName || '-' }}</strong>
          </div>
          <div class="info-item">
            <span>角色 ID</span>
            <strong>{{ roleId || '-' }}</strong>
          </div>
          <div class="info-item">
            <span>订单号</span>
            <strong>{{ order?.platformOrderId || '-' }}</strong>
          </div>
          <div class="info-item">
            <span>购买数量</span>
            <strong>{{ orderItem?.quantity || 0 }}</strong>
          </div>
        </div>

        <div class="status-banner success">
          <el-icon><CircleCheck /></el-icon>
          <span>客户侧操作已经完成，后续履约结果请以后台任务界面为准。</span>
        </div>
      </section>
    </template>

    <div v-else class="content-card error-card">
      <el-icon class="large-icon error"><CircleClose /></el-icon>
      <p>流程数据不完整，请联系客服处理</p>
    </div>
  </main>
</template>

<style scoped>
.claim-page {
  min-height: 100vh;
  padding: 24px;
  background:
    radial-gradient(circle at top right, rgba(59, 130, 246, 0.18), transparent 28%),
    linear-gradient(180deg, #f8fafc 0%, #eef4fb 100%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
}

.header-card,
.summary-card,
.content-card {
  width: 100%;
  max-width: 680px;
  background: rgba(255, 255, 255, 0.92);
  border: 1px solid rgba(148, 163, 184, 0.16);
  border-radius: 20px;
  box-shadow: 0 18px 40px rgba(15, 23, 42, 0.08);
  backdrop-filter: blur(12px);
}

.header-card {
  padding: 24px 28px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
}

.header-copy h1,
.content-card h2 {
  margin: 0;
  color: #0f172a;
}

.header-copy p,
.muted {
  margin: 0;
  color: #64748b;
  line-height: 1.6;
}

.eyebrow {
  display: inline-flex;
  margin-bottom: 8px;
  color: #2563eb;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.08em;
}

.step-indicator {
  display: flex;
  gap: 10px;
}

.step-dot {
  width: 34px;
  height: 34px;
  border-radius: 999px;
  background: #e2e8f0;
  color: #94a3b8;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
}

.step-dot.active {
  background: linear-gradient(135deg, #2563eb 0%, #0ea5e9 100%);
  color: #ffffff;
}

.summary-card {
  padding: 18px 22px;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
}

.summary-item,
.info-item {
  padding: 16px;
  border-radius: 16px;
  background: #f8fafc;
  border: 1px solid #e2e8f0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.summary-item span,
.info-item span {
  color: #64748b;
  font-size: 13px;
}

.summary-item strong,
.info-item strong {
  color: #0f172a;
  font-size: 17px;
}

.content-card {
  padding: 28px;
  display: flex;
  flex-direction: column;
  gap: 18px;
}

.loading-card,
.error-card {
  align-items: center;
  justify-content: center;
  text-align: center;
  min-height: 240px;
}

.large-icon {
  font-size: 44px;
}

.large-icon.success {
  color: #16a34a;
}

.large-icon.error {
  color: #dc2626;
}

.spinning {
  animation: spin 1s linear infinite;
}

.status-banner {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 14px 16px;
  border-radius: 14px;
  font-size: 14px;
}

.status-banner.info {
  background: #eff6ff;
  color: #1d4ed8;
}

.status-banner.success {
  background: #f0fdf4;
  color: #166534;
}

.status-banner.warning {
  background: #fff7ed;
  color: #c2410c;
}

.status-banner.error {
  background: #fef2f2;
  color: #b91c1c;
}

.guide-grid,
.info-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

.guide-figure {
  margin: 0;
  background: #f8fafc;
  border: 1px solid #e2e8f0;
  border-radius: 16px;
  overflow: hidden;
}

.guide-figure img {
  width: 100%;
  display: block;
}

.guide-figure figcaption {
  padding: 10px 12px 14px;
  color: #475569;
  font-size: 13px;
}

.qr-block {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  padding: 22px;
  border-radius: 18px;
  background: linear-gradient(180deg, #eff6ff 0%, #f8fafc 100%);
  border: 1px solid #dbeafe;
}

.qr-code {
  width: 280px;
  height: 280px;
  padding: 12px;
  background: #ffffff;
  border-radius: 18px;
}

.action-row {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
}

.warning-line {
  color: #b45309;
}

.meta-line {
  font-size: 13px;
}

.result-header {
  display: flex;
  align-items: flex-start;
  gap: 14px;
}

@keyframes spin {
  from {
    transform: rotate(0deg);
  }

  to {
    transform: rotate(360deg);
  }
}

@media (max-width: 720px) {
  .claim-page {
    padding: 16px;
  }

  .header-card,
  .summary-card,
  .content-card {
    max-width: 100%;
  }

  .header-card {
    flex-direction: column;
    align-items: flex-start;
  }

  .summary-card,
  .guide-grid,
  .info-grid {
    grid-template-columns: 1fr;
  }

  .qr-code {
    width: min(280px, 100%);
    height: auto;
  }

  .action-row {
    width: 100%;
    flex-direction: column;
  }
}
</style>
