<template>
  <view class="lazy-image-wrapper" :style="wrapperStyle">
    <image
      v-if="shouldLoad"
      :src="currentSrc"
      :mode="mode"
      :class="['lazy-image', { 'loaded': isLoaded, 'error': hasError }]"
      :style="imageStyle"
      @load="handleLoad"
      @error="handleError"
    />
    <view v-else class="lazy-image-placeholder" :style="placeholderStyle">
      <view class="placeholder-icon"></view>
    </view>
  </view>
</template>

<script setup>
import { ref, computed, onMounted, onUnmounted, getCurrentInstance, watch, inject } from 'vue'

const props = defineProps({
  src: {
    type: String,
    required: true
  },
  placeholder: {
    type: String,
    default: ''
  },
  mode: {
    type: String,
    default: 'aspectFill'
  },
  width: {
    type: [String, Number],
    default: '100%'
  },
  height: {
    type: [String, Number],
    default: 'auto'
  },
  lazy: {
    type: Boolean,
    default: true
  },
  threshold: {
    type: Number,
    default: 100 // 距离可视区域多少像素时开始加载
  },
  // 用于虚拟列表场景的滚动触发（可选，优先使用 inject）
  scrollTop: {
    type: Number,
    default: 0
  }
})

const emit = defineEmits(['load', 'error'])

const shouldLoad = ref(!props.lazy) // 如果不启用懒加载，直接加载
const isLoaded = ref(false)
const hasError = ref(false)
const checkTimer = ref(null)
const instance = getCurrentInstance()

// 尝试从 VirtualList 注入 scrollTop（用于虚拟列表场景）
const injectedScrollTop = inject('virtualListScrollTop', null)

const currentSrc = computed(() => {
  if (hasError.value && props.placeholder) {
    return props.placeholder
  }
  return props.src
})

const wrapperStyle = computed(() => {
  const style = {}
  if (props.width) {
    style.width = typeof props.width === 'number' ? `${props.width}px` : props.width
  }
  if (props.height) {
    style.height = typeof props.height === 'number' ? `${props.height}px` : props.height
  }
  return style
})

const imageStyle = computed(() => {
  return {
    width: '100%',
    height: '100%'
  }
})

const placeholderStyle = computed(() => {
  return {
    width: '100%',
    height: '100%',
    backgroundColor: '#f5f5f5'
  }
})

function handleLoad(e) {
  isLoaded.value = true
  hasError.value = false
  emit('load', e)
}

function handleError(e) {
  hasError.value = true
  console.error('[LazyImage] 图片加载失败:', props.src)
  emit('error', e)
}

// 检查元素是否在可视区域内
function checkInView() {
  if (!props.lazy || shouldLoad.value) {
    return
  }

  const query = uni.createSelectorQuery().in(instance)
  query.select('.lazy-image-wrapper').boundingClientRect((rect) => {
    if (!rect) return

    const windowHeight = uni.getSystemInfoSync().windowHeight
    const threshold = props.threshold

    // 判断元素是否在可视区域内或即将进入可视区域
    if (rect.top < windowHeight + threshold && rect.bottom > -threshold) {
      shouldLoad.value = true
      stopChecking()
    }
  }).exec()
}

// 停止检查
function stopChecking() {
  if (checkTimer.value) {
    clearTimeout(checkTimer.value)
    checkTimer.value = null
  }
}

// 设置懒加载
function setupLazyLoad() {
  if (!props.lazy) {
    shouldLoad.value = true
    return
  }

  // 首次检查
  checkInView()

  // 如果首次检查未加载，设置延迟检查
  if (!shouldLoad.value) {
    checkTimer.value = setTimeout(() => {
      checkInView()
      checkTimer.value = null
    }, 500)
  }
}

// 监听 src 变化，重新设置懒加载
watch(() => props.src, () => {
  if (props.lazy && !shouldLoad.value) {
    setupLazyLoad()
  }
})

onMounted(() => {
  setupLazyLoad()
  
  // 在 onMounted 后设置 watch，确保 inject 已经准备好
  // 监听注入的 scrollTop（来自 VirtualList）
  if (injectedScrollTop) {
    watch(injectedScrollTop, () => {
      if (!shouldLoad.value && props.lazy) {
        checkInView()
      }
    }, { immediate: false })
  }
  
  // 监听 prop scrollTop 变化（用于手动传递的场景）
  watch(() => props.scrollTop, () => {
    if (!shouldLoad.value && props.lazy) {
      checkInView()
    }
  }, { immediate: false })
})

onUnmounted(() => {
  stopChecking()
})
</script>

<style scoped>
.lazy-image-wrapper {
  position: relative;
  overflow: hidden;
  display: inline-block;
}

.lazy-image {
  display: block;
  opacity: 0;
  transition: opacity 0.3s ease-in-out;
}

.lazy-image.loaded {
  opacity: 1;
}

.lazy-image.error {
  opacity: 0.5;
}

.lazy-image-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #f5f5f5;
}

.placeholder-icon {
  width: 60rpx;
  height: 60rpx;
  border-radius: 50%;
  background-color: #e0e0e0;
  animation: pulse 1.5s ease-in-out infinite;
}

@keyframes pulse {
  0%, 100% {
    opacity: 1;
  }
  50% {
    opacity: 0.5;
  }
}
</style>
