<template>
  <scroll-view
    class="waterfall-scroll"
    :style="scrollStyle"
    scroll-x
    :show-scrollbar="false"
    :scroll-left="scrollLeft"
    @scroll="onScroll"
    @touchstart="onTouchStart"
    @touchend="onTouchEnd"
    @touchcancel="onTouchEnd"
  >
    <view class="waterfall-inner" :style="{ width: totalWidth + 'px', height: '100%' }">
      <view
        v-for="card in cards"
        :key="card.id"
        class="wf-card"
        :style="cardStyle(card)"
        @click="handleCardClick(card)"
      >
        <!-- 渐变边框光效 -->
        <view class="wf-card-border" :style="borderStyle(card)" />

        <!-- 封面图 -->
        <image
          v-if="card.coverUrl"
          class="wf-card-img"
          :src="card.coverUrl"
          mode="aspectFill"
          :style="{ width: card.w + 'px', height: card.h + 'px', borderRadius: card.radius + 'px' }"
        />

        <!-- 底部点赞数 -->
        <view class="wf-card-footer">
          <image class="wf-heart" src="/static/icon/heart-icon.png" mode="aspectFit" />
          <view class="wf-likes-wrap">
            <text class="wf-likes">{{ formatLikes(card.likes) }}</text>
          </view>
        </view>
      </view>
    </view>
  </scroll-view>
</template>

<script setup>
import { ref, computed, watch, onMounted, onUnmounted } from 'vue'
import { getRandomUsersApi, getOssPresignedUrlApi } from '@/utils/api.js'

const props = defineProps({
  screenWidth: { type: Number, default: 375 },
  screenHeight: { type: Number, default: 812 },
  bannerBottom: { type: Number, default: 200 },
})

const emit = defineEmits(['cardClick'])

// ========== 布局常量 ==========
const rpx2px = (rpx) => Math.round(uni.getSystemInfoSync().windowWidth / 750 * rpx)
const GAP = rpx2px(16)
const BORDER_W = rpx2px(2)
const SCALE = 0.9
const ROWS = 4
const AUTO_SCROLL_SPEED = 1.2
const AUTO_RESUME_DELAY = 2500
const PRELOAD_THRESHOLD = rpx2px(1200)

// ========== 状态 ==========
const cards = ref([])
const allUsers = ref([])
const totalWidth = ref(0)
const scrollLeft = ref(0)
let currentScrollLeft = 0
let idCounter = 0

// ========== RAF 兼容 ==========
const rafFn = (cb) => {
  if (typeof requestAnimationFrame !== 'undefined') return requestAnimationFrame(cb)
  if (uni.requestAnimationFrame) return uni.requestAnimationFrame(cb)
  return setTimeout(cb, 16)
}
const cafFn = (id) => {
  if (typeof cancelAnimationFrame !== 'undefined') return cancelAnimationFrame(id)
  if (uni.cancelAnimationFrame) return uni.cancelAnimationFrame(id)
  clearTimeout(id)
}

// ========== 自动滚动 ==========
let rafId = null
let userInteracting = false
let resumeTimer = null

const startAutoScroll = () => {
  if (rafId) return
  const step = () => {
    if (!userInteracting) {
      currentScrollLeft += AUTO_SCROLL_SPEED
      scrollLeft.value = currentScrollLeft
      if (totalWidth.value - currentScrollLeft - props.screenWidth < PRELOAD_THRESHOLD) {
        appendMore()
      }
    }
    rafId = rafFn(step)
  }
  rafId = rafFn(step)
}

const stopAutoScroll = () => {
  if (rafId) { cafFn(rafId); rafId = null }
}

const pauseForUser = () => {
  userInteracting = true
  clearTimeout(resumeTimer)
  resumeTimer = setTimeout(() => { userInteracting = false }, AUTO_RESUME_DELAY)
}

// ========== 触摸 / 滚动事件 ==========
const onTouchStart = () => pauseForUser()
const onTouchEnd = () => {}

const onScroll = (e) => {
  currentScrollLeft = e.detail.scrollLeft
  if (totalWidth.value - currentScrollLeft - props.screenWidth < PRELOAD_THRESHOLD) {
    appendMore()
  }
}

// ========== 样式 ==========
const scrollStyle = computed(() => ({
  position: 'absolute',
  top: props.bannerBottom + 'px',
  left: 0,
  width: props.screenWidth + 'px',
  height: (props.screenHeight - props.bannerBottom) + 'px',
  zIndex: 2,
  overflow: 'hidden',
}))

// ========== 布局引擎 ==========
// 核心思路：按列放置，每列的卡片 span 之和 = ROWS，保证零空缺
// 同一列内所有卡片宽度统一 = 整列宽（span=ROWS 对应的宽），高度各自按 span 计算
// 支持两种模式：
//   1. 后端传 span：直接按 span 分组成列
//   2. 后端不传 span：前端随机选列模板，每次打开都不同
class WaterfallLayout {
  constructor(containerH, gap = GAP) {
    this.containerH = containerH
    this.gap = gap
    this.rowH = Math.floor((containerH - gap * (ROWS - 1)) / ROWS)
    // 列宽固定 = rowH × 9/16，严格竖长 9:16，span 只影响高度
    this.colW = Math.round(this.rowH * 9 / 16)
    this.curX = 0
  }

  _cardSize(span) {
    const h = Math.round((span * this.rowH + (span - 1) * this.gap) * SCALE)
    const w = Math.round(h * 9 / 16)
    return { w, h }
  }

  // 点赞数 → span
  _span(likes) {
    if (likes < 500)   return 1
    if (likes < 2000)  return 2
    if (likes < 8000)  return 2
    if (likes < 50000) return 3
    return 4
  }

  // 将用户列表按点赞数决定 span，分组成列，每列 span 之和 = ROWS
  _groupIntoColumns(users) {
    const columns = []
    let i = 0
    while (i < users.length) {
      const col = []
      let sum = 0
      while (i < users.length && sum < ROWS) {
        // 后端有 span 用后端的，否则按点赞数算
        const rawSpan = users[i].span != null ? users[i].span : this._span(users[i].likes || 0)
        const span = Math.min(rawSpan, ROWS - sum)
        col.push({ ...users[i], span })
        sum += span
        i++
      }
      // 凑不满则补 _pad
      while (sum < ROWS) {
        col.push({ id: idCounter++, span: 1, _pad: true, likes: 0 })
        sum++
      }
      columns.push(col)
    }
    return columns
  }

  _placeColumn(colUsers) {
    const result = []
    let curY = 0
    const colX = this.curX
    const maxSpan = Math.max(...colUsers.map(u => u.span || 1))
    const colW = this._cardSize(maxSpan).w

    for (const u of colUsers) {
      const span = u.span || 1
      const { w, h } = this._cardSize(span)
      if (!u._pad) {
        result.push({ ...u, left: colX, top: curY, w, h, radius: 8 })
      }
      curY += h + this.gap
    }

    this.curX += colW + this.gap
    return result
  }

  // 计算全部卡片布局（重置状态）
  compute(users) {
    this.curX = 0
    const columns = this._groupIntoColumns(users)
    const result = []
    for (const col of columns) {
      result.push(...this._placeColumn(col))
    }
    return result
  }

  // 追加更多卡片（保持当前 X 继续）
  addCards(users) {
    const columns = this._groupIntoColumns(users)
    const result = []
    for (const col of columns) {
      result.push(...this._placeColumn(col))
    }
    return result
  }

  getTotalWidth() {
    return this.curX
  }
}

let layout = null

// ========== 颜色主题 ==========
const PALETTES = [
  'linear-gradient(135deg, #2d1b69, #5b21b6)',
  'linear-gradient(135deg, #0c4a6e, #0284c7)',
  'linear-gradient(135deg, #450a0a, #b91c1c)',
  'linear-gradient(135deg, #064e3b, #059669)',
  'linear-gradient(135deg, #78350f, #d97706)',
  'linear-gradient(135deg, #4a1942, #be185d)',
]

const BORDER_COLORS = [
  'linear-gradient(135deg, #a78bfa, #60a5fa)',
  'linear-gradient(135deg, #38bdf8, #818cf8)',
  'linear-gradient(135deg, #f472b6, #fb923c)',
  'linear-gradient(135deg, #4ade80, #22d3ee)',
  'linear-gradient(135deg, #fbbf24, #f87171)',
  'linear-gradient(135deg, #c084fc, #f472b6)',
]

// ========== 样式函数 ==========
const cardStyle = (card) => ({
  position: 'absolute',
  left: card.left + 'px',
  top: card.top + 'px',
  width: card.w + 'px',
  height: card.h + 'px',
  borderRadius: card.radius + 'px',
  overflow: 'hidden',
  background: card.coverUrl ? 'transparent' : PALETTES[Math.abs(card.id) % PALETTES.length],
})

const borderStyle = (card) => ({
  position: 'absolute',
  inset: `-${BORDER_W}px`,
  borderRadius: (card.radius + BORDER_W) + 'px',
  background: BORDER_COLORS[Math.abs(card.id) % BORDER_COLORS.length],
  zIndex: 0,
  opacity: 0.85,
})

const formatLikes = (n) => {
  if (n >= 10000) return (n / 10000).toFixed(1) + 'w'
  if (n >= 1000) return (n / 1000).toFixed(1) + 'k'
  return String(n)
}

// ========== 数据加载 ==========
let isLoadingMore = false

// 后端不返回 likes 时，前端随机模拟
const randomLikes = () => {
  const r = Math.random()
  if (r < 0.20) return Math.floor(Math.random() * 100)
  if (r < 0.40) return Math.floor(100 + Math.random() * 400)
  if (r < 0.60) return Math.floor(500 + Math.random() * 1500)
  if (r < 0.75) return Math.floor(2000 + Math.random() * 6000)
  if (r < 0.90) return Math.floor(8000 + Math.random() * 42000)
  return Math.floor(50000 + Math.random() * 950000)
}

// 本地素材图，循环使用
const MOCK_IMAGES = Array.from({ length: 16 }, (_, i) => `/static/sucai/image-${String(i + 1).padStart(2, '0')}.png`)

const mapUser = async (u) => {
  // 优先用后端图，没有则用本地素材循环
  let coverUrl = MOCK_IMAGES[idCounter % MOCK_IMAGES.length]
  if (u.cover_url) {
    try {
      const r = await getOssPresignedUrlApi(u.cover_url, 3600, 'asset')
      if (r?.code === 200 && r.data?.url) coverUrl = r.data.url
    } catch (_) {}
  }
  // 后端可以返回 span 字段（1~4）来控制卡片大小，不传则前端随机模板决定
  return {
    id: idCounter++,
    userId: u.user_id,
    nickname: u.nickname,
    coverUrl,
    likes: u.likes ?? randomLikes(),
    span: u.span ?? null,  // 后端控制字段，null = 前端随机模板决定
  }
}

const loadUsers = async () => {
  try {
    const res = await getRandomUsersApi(1, 40)
    if (res.code === 200 && res.data?.users) {
      const withData = await Promise.all(res.data.users.map(mapUser))
      allUsers.value = withData
      cards.value = layout.compute(withData)
      totalWidth.value = layout.getTotalWidth()
    }
  } catch (e) {
    console.error('[WaterfallGrid] 加载用户失败', e?.message ?? e)
  }
}

const appendMore = async () => {
  if (isLoadingMore) return
  isLoadingMore = true
  try {
    const res = await getRandomUsersApi(1, 20)
    if (res.code === 200 && res.data?.users) {
      const withData = await Promise.all(res.data.users.map(mapUser))
      const placed = layout.addCards(withData)
      cards.value = [...cards.value, ...placed]
      totalWidth.value = layout.getTotalWidth()
    }
  } catch (e) {
    console.error('[WaterfallGrid] 追加用户失败', e?.message ?? e)
  } finally {
    isLoadingMore = false
  }
}

// ========== 点击处理 ==========
const handleCardClick = (card) => {
  if (userInteracting) return
  emit('cardClick', card)
}

// ========== 初始化 ==========
onMounted(() => {
  const containerH = props.screenHeight - props.bannerBottom
  layout = new WaterfallLayout(containerH)
  loadUsers().then(() => startAutoScroll())
})

onUnmounted(() => {
  stopAutoScroll()
  clearTimeout(resumeTimer)
})

watch(() => [props.screenHeight, props.bannerBottom], () => {
  const containerH = props.screenHeight - props.bannerBottom
  layout = new WaterfallLayout(containerH)
  if (allUsers.value.length) {
    cards.value = layout.compute(allUsers.value)
    totalWidth.value = layout.getTotalWidth()
  }
})
</script>

<style scoped>
.waterfall-scroll {
  white-space: nowrap;
}

.waterfall-inner {
  position: relative;
  height: 100%;
  display: inline-block;
}

.wf-card {
  position: absolute;
  cursor: pointer;
  will-change: transform;
  transform-origin: top center;
}

.wf-card:active {
  transform: scale(0.96);
}

.wf-card-border {
  position: absolute;
  pointer-events: none;
}

.wf-card-img {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 1;
  display: block;
}

.wf-card-footer {
  position: absolute;
  bottom: 8rpx;
  left: 10rpx;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: 4rpx;
}

.wf-heart {
  width: 28rpx;
  height: 28rpx;
}

.wf-likes-wrap {
  background: linear-gradient(to bottom right,
    #F0E4B1 0%,
    #F08399 50%,
    #B94E73 100%
  );
  border-radius: 999rpx;
  padding: 2rpx 10rpx;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow:
    0 4rpx 12rpx rgba(255, 143, 158, 0.2),
    inset 0 2rpx 4rpx rgba(255, 255, 255, 0.4);
}

.wf-likes {
  font-size: 18rpx;
  font-weight: 700;
  color: #ffffff;
}
</style>
