<template>
  <view class="qr-scanner-page">
    <!-- 顶部导航 -->
    <view class="qr-scanner-nav">
      <view class="qr-scanner-nav-back" @click="goBack">
        <text class="qr-scanner-nav-back-icon">&larr;</text>
      </view>
      <text class="qr-scanner-nav-title">扫描二维码</text>
      <view class="qr-scanner-nav-placeholder" />
    </view>

    <!-- 相机区域 -->
    <view class="qr-scanner-viewfinder">
      <view id="qr-reader" class="qr-scanner-reader" />

      <!-- 扫描框覆盖层 -->
      <view class="qr-scanner-overlay">
        <view class="qr-scanner-corner qr-scanner-corner--tl" />
        <view class="qr-scanner-corner qr-scanner-corner--tr" />
        <view class="qr-scanner-corner qr-scanner-corner--bl" />
        <view class="qr-scanner-corner qr-scanner-corner--br" />
        <view class="qr-scanner-line" />
      </view>

      <!-- 相机未授权时的提示 -->
      <view v-if="cameraError" class="qr-scanner-camera-error">
        <view class="qr-scanner-camera-error-icon">
          <AiIcon icon="/static/icons/ai-icon/alert-triangle.svg" color="#f59e0b" size="lg" />
        </view>
        <text class="qr-scanner-camera-error-title">无法访问摄像头</text>
        <text class="qr-scanner-camera-error-desc">{{ cameraErrorMsg }}</text>
        <view class="qr-scanner-camera-error-actions">
          <AiButton size="sm" @click="startScanner">重试</AiButton>
        </view>
      </view>
    </view>

    <!-- 底部提示 -->
    <view class="qr-scanner-footer">
      <text class="qr-scanner-footer-text">将二维码放入框内，即可自动扫描</text>
      <view class="qr-scanner-footer-actions">
        <view class="qr-scanner-footer-btn" @click="handleAlbum">
          <AiIcon icon="/static/icons/ai-icon/image.svg" color="#ffffff" size="sm" />
          <text class="qr-scanner-footer-btn-text">从相册选择</text>
        </view>
      </view>
    </view>
  </view>
</template>

<script setup>
import { onMounted, onBeforeUnmount, ref } from 'vue'
import AiIcon from '@/components/AiIcon.vue'
import AiButton from '@/components/AiButton.vue'
import { Html5Qrcode, Html5QrcodeScanType } from 'html5-qrcode'
import { toast } from '@/utils/notify'

const cameraError = ref(false)
const cameraErrorMsg = ref('')
let html5QrCode = null
let isDestroyed = false

onMounted(() => {
  startScanner()
})

onBeforeUnmount(() => {
  stopScanner()
})

async function startScanner() {
  cameraError.value = false
  cameraErrorMsg.value = ''

  try {
    if (html5QrCode) {
      try {
        await html5QrCode.stop()
      } catch (e) {
        // ignore
      }
      html5QrCode.clear()
      html5QrCode = null
    }

    html5QrCode = new Html5Qrcode('qr-reader', { verbose: false })

    const config = {
      fps: 15,
      qrbox: (viewfinderWidth, viewfinderHeight) => {
        const minEdge = Math.min(viewfinderWidth, viewfinderHeight)
        const size = Math.floor(minEdge * 0.7)
        return { width: size, height: size }
      },
      aspectRatio: 1.0,
    }

    // 优先使用后置摄像头
    const cameras = await Html5Qrcode.getCameras()
    if (!cameras || cameras.length === 0) {
      throw new Error('未检测到摄像头设备')
    }

    let cameraId = cameras[0].id
    // 查找后置摄像头
    const backCamera = cameras.find(c =>
      /back|rear|environment/i.test(c.label)
    )
    if (backCamera) {
      cameraId = backCamera.id
    }

    await html5QrCode.start(
      cameraId,
      config,
      onScanSuccess,
      () => { /* onScanFailure - ignore */ }
    )
  } catch (err) {
    console.error('Camera error:', err)
    cameraError.value = true

    if (err.name === 'NotAllowedError' || err.message?.includes('Permission')) {
      cameraErrorMsg.value = '请在浏览器设置中允许访问摄像头'
    } else if (err.name === 'NotFoundError' || err.message?.includes('未检测')) {
      cameraErrorMsg.value = '未检测到摄像头设备，请确认设备已连接'
    } else if (err.name === 'NotReadableError') {
      cameraErrorMsg.value = '摄像头被占用，请关闭其他应用后重试'
    } else if (err.message?.includes('HTTPS') || err.message?.includes('secure')) {
      cameraErrorMsg.value = '摄像头功能需要 HTTPS 或 localhost 环境'
    } else {
      cameraErrorMsg.value = err.message || '摄像头启动失败'
    }
  }
}

async function stopScanner() {
  isDestroyed = true
  if (html5QrCode) {
    try {
      if (html5QrCode.isScanning) {
        await html5QrCode.stop()
      }
    } catch (e) {
      // ignore
    }
    try {
      html5QrCode.clear()
    } catch (e) {
      // ignore
    }
    html5QrCode = null
  }
}

function onScanSuccess(decodedText) {
  // 扫码成功，震动反馈
  uni.vibrateShort()

  const params = parseQrUrl(decodedText)
  if (params) {
    stopScanner()
    uni.redirectTo({
      url: `/pages/hotel/scan-bind?c=${params.c}&t=${params.t}&s=${params.s}`,
    })
  } else {
    toast('无法识别该二维码，请扫描酒店房间二维码', { type: 'warning' })
  }
}

function parseQrUrl(url) {
  try {
    const matchC = url.match(/[?&]c=([^&]+)/)
    const matchT = url.match(/[?&]t=([^&]+)/)
    const matchS = url.match(/[?&]s=([^&]+)/)
    if (matchC && matchS) {
      return {
        c: matchC[1],
        t: matchT ? matchT[1] : '1',
        s: matchS[1],
      }
    }
  } catch (e) {
    // ignore
  }
  return null
}

function goBack() {
  uni.navigateBack({ delta: 1 })
}

async function handleAlbum() {
  if (!html5QrCode) return

  try {
    // 暂停实时扫描
    if (html5QrCode.isScanning) {
      await html5QrCode.pause(/* shouldPauseResume */true)
    }

    // 使用 html5-qrcode 的文件扫描功能
    const input = document.createElement('input')
    input.type = 'file'
    input.accept = 'image/*'
    input.capture = 'environment'
    input.style.display = 'none'

    input.onchange = async (e) => {
      const file = e.target.files?.[0]
      if (!file) {
        resumeScanner()
        return
      }

      try {
        const result = await html5QrCode.scanFileV2(file, {
          formatsSupported: Object.values(Html5QrcodeScanType),
        })
        onScanSuccess(result)
      } catch (err) {
        toast('未能从图片中识别二维码', { type: 'warning' })
        resumeScanner()
      } finally {
        input.remove()
      }
    }

    input.oncancel = () => {
      resumeScanner()
      input.remove()
    }

    document.body.appendChild(input)
    input.click()
  } catch (err) {
    console.error('Album scan error:', err)
    toast('打开相册失败', { type: 'error' })
    resumeScanner()
  }
}

async function resumeScanner() {
  if (html5QrCode && !isDestroyed) {
    try {
      await html5QrCode.resume()
    } catch (e) {
      // ignore
    }
  }
}
</script>

<style lang="scss" scoped>
.qr-scanner-page {
  position: relative;
  min-height: 100vh;
  background: #000;
  display: flex;
  flex-direction: column;
}

// Nav
.qr-scanner-nav {
  position: relative;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 24rpx;
  padding-top: env(safe-area-inset-top, 44px);
  height: calc(88rpx + env(safe-area-inset-top, 44px));
  background: rgba(0, 0, 0, 0.6);
}

.qr-scanner-nav-back {
  width: 72rpx;
  height: 72rpx;
  display: flex;
  align-items: center;
  justify-content: center;
}

.qr-scanner-nav-back-icon {
  color: #fff;
  font-size: 40rpx;
}

.qr-scanner-nav-title {
  color: #fff;
  font-size: 32rpx;
  font-weight: 700;
}

.qr-scanner-nav-placeholder {
  width: 72rpx;
}

// Viewfinder
.qr-scanner-viewfinder {
  flex: 1;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.qr-scanner-reader {
  width: 100%;
  max-width: 600rpx;
  aspect-ratio: 1;

  :deep(video) {
    width: 100% !important;
    height: 100% !important;
    object-fit: cover;
    border-radius: 24rpx;
  }

  :deep(#qr-reader-dashboard) {
    display: none !important;
  }

  :deep(#qr-reader-status-container) {
    display: none !important;
  }
}

// Overlay with corners
.qr-scanner-overlay {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 70%;
  aspect-ratio: 1;
  pointer-events: none;
}

.qr-scanner-corner {
  position: absolute;
  width: 48rpx;
  height: 48rpx;
  border-color: #2563eb;
  border-style: solid;
  border-width: 0;

  &--tl {
    top: 0;
    left: 0;
    border-top-width: 6rpx;
    border-left-width: 6rpx;
    border-top-left-radius: 16rpx;
  }

  &--tr {
    top: 0;
    right: 0;
    border-top-width: 6rpx;
    border-right-width: 6rpx;
    border-top-right-radius: 16rpx;
  }

  &--bl {
    bottom: 0;
    left: 0;
    border-bottom-width: 6rpx;
    border-left-width: 6rpx;
    border-bottom-left-radius: 16rpx;
  }

  &--br {
    bottom: 0;
    right: 0;
    border-bottom-width: 6rpx;
    border-right-width: 6rpx;
    border-bottom-right-radius: 16rpx;
  }
}

.qr-scanner-line {
  position: absolute;
  left: 5%;
  right: 5%;
  height: 4rpx;
  background: linear-gradient(90deg, transparent, #2563eb, transparent);
  animation: scanLine 2.5s ease-in-out infinite;
}

@keyframes scanLine {
  0%, 100% { top: 5%; }
  50% { top: 95%; }
}

// Camera error
.qr-scanner-camera-error {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16rpx;
  background: rgba(0, 0, 0, 0.85);
  padding: 40rpx;
}

.qr-scanner-camera-error-icon {
  margin-bottom: 8rpx;
}

.qr-scanner-camera-error-title {
  color: #fff;
  font-size: 32rpx;
  font-weight: 700;
}

.qr-scanner-camera-error-desc {
  color: #94a3b8;
  font-size: 26rpx;
  text-align: center;
  margin-bottom: 16rpx;
}

.qr-scanner-camera-error-actions {
  margin-top: 8rpx;
}

// Footer
.qr-scanner-footer {
  position: relative;
  z-index: 20;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 24rpx;
  padding: 40rpx 0;
  padding-bottom: calc(40rpx + env(safe-area-inset-bottom));
  background: rgba(0, 0, 0, 0.6);
}

.qr-scanner-footer-text {
  color: rgba(255, 255, 255, 0.7);
  font-size: 26rpx;
  font-weight: 500;
}

.qr-scanner-footer-actions {
  display: flex;
  gap: 32rpx;
}

.qr-scanner-footer-btn {
  display: flex;
  align-items: center;
  gap: 8rpx;
  padding: 16rpx 32rpx;
  border-radius: 40rpx;
  background: rgba(255, 255, 255, 0.15);
  border: 1rpx solid rgba(255, 255, 255, 0.2);

  &:active {
    background: rgba(255, 255, 255, 0.25);
  }
}

.qr-scanner-footer-btn-text {
  color: #fff;
  font-size: 26rpx;
  font-weight: 600;
}
</style>
