<script setup lang="ts">
import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'
import { onBeforeRouteLeave, RouterLink, useRoute, useRouter } from 'vue-router'
import MobileBottomNav from '@/components/MobileBottomNav.vue'
import { ensureSupportChat, resolveSupportScene } from '@/features/chats/api/chats'
import { formatCent, formatMoney } from '@/shared/utils/money'
import {
  emptyListingPublishOptions,
  type ListingPublishOptions,
} from '@/features/listings/api/listingOptions'
import {
  fetchListingsPage,
  type Listing,
  type PublicListingQuery,
} from '@/features/listings/api/listings'
import {
  defaultAWRecycleConfig,
  defaultCooperationFeedbackConfig,
  defaultHomeAnnouncements,
  defaultHomeBanners,
  fetchMobileHomeConfig,
  type AWRecycleConfig,
  type CooperationFeedbackConfig,
  type HomeBannerSlide,
} from '@/features/listings/api/homeConfig'
import { showImagePreview, showToast } from 'vant'
import AuthImage from '@/shared/components/business/AuthImage.vue'
import MobileHomeFilterSheet, { type FilterSection } from './MobileHomeFilterSheet.vue'
import {
  clearStoredHomeQuery,
  decodeHomeQueryJson,
  encodeHomeQueryJson,
  hasHomeQueryValues,
  isSameQuery,
  mergeHomeQuery,
  mobileHomeFilterStorageKey,
  mobileHomeFilterQueryKeys,
  readStoredHomeQuery,
  readQueryString,
  storeHomeQuery,
  type HomeQueryValue,
} from '@/features/listings/composables/useHomeFilterQuery'
import {
  getListingChips,
  getListingDisplayPrice,
  getListingTitle,
  getDailyLoss,
  getRatioValue,
  formatListingCode,
  formatEstimatedRentalDuration,
  getLoginMethod,
  getServerRegion,
  assetRegions,
  hasAcceleratedSaleRatio,
  hasGiftResources,
} from '@/shared/utils/listingDisplay'
import { buildMobileHomeListSignature, useMobileHomeCacheStore } from '@/stores/mobileHomeCache'
import { useSessionStore } from '@/stores/session'

const router = useRouter()
const route = useRoute()
const session = useSessionStore()
const homeCache = useMobileHomeCacheStore()
const scrollEl = ref<HTMLElement | null>(null)
const loading = ref(false)
const loadingMore = ref(false)
const loadFailed = ref(false)
const listings = ref<Listing[]>([])
const totalListings = ref(0)
const zoneCounts = ref<Record<string, number>>({})
const currentPage = ref(1)
const hasMoreListings = ref(true)
const publishOptions = ref<ListingPublishOptions>(emptyListingPublishOptions)
const sortOpen = ref(false)
const activeSort = ref('recommended')
const activeZone = ref('all')
const filterOpen = ref(false)
const selectedFilters = ref<Record<string, string[]>>({})
const rangeFilters = ref<Record<string, { min: string; max: string }>>({})
const refreshing = ref(false)
const searchValue = ref('')
const announcements = ref<string[]>(defaultHomeAnnouncements)
const bannerSlides = ref<HomeBannerSlide[]>(defaultHomeBanners)
const awRecycle = ref<AWRecycleConfig>({ ...defaultAWRecycleConfig })
const awRecyclePreviewVisible = ref(false)
const cooperationFeedback = ref<CooperationFeedbackConfig>({ ...defaultCooperationFeedbackConfig })
const cooperationFeedbackPreviewVisible = ref(false)
const supportLoading = ref(false)
const showBackTop = ref(false)
const mobilePageSize = 10
let listingRequestSeq = 0
let searchDebounceTimer: ReturnType<typeof setTimeout> | null = null

const sortOptions = [
  { key: 'recommended', label: '综合推荐' },
  { key: 'coinDesc', label: '哈夫币' },
  { key: 'awmDesc', label: 'AWM数量' },
  { key: 'priceAsc', label: '价格最低' },
  { key: 'priceDesc', label: '价格最高' },
  { key: 'published', label: '最新发布' },
]

const zoneOptions = [
  { key: 'all', label: '全部', hint: '当前可租' },
  { key: 'sale', label: '特惠', hint: '价格更划算' },
  { key: 'gift', label: '赠送', hint: '含赠送物品' },
  { key: 'night', label: '夜间', hint: '0-2点可响应上号' },
  { key: 'password', label: '账密', hint: '交接更快' },
  { key: 'highCoin', label: '高币', hint: '100M以上' },
]

const rangePresets: Record<string, Array<{ label: string; min: string; max: string }>> = {
  price: [
    { label: '0-50', min: '0', max: '50' },
    { label: '50-100', min: '50', max: '100' },
    { label: '100-200', min: '100', max: '200' },
    { label: '200以上', min: '200', max: '' },
  ],
  coin: [
    { label: '0-100', min: '0', max: '100' },
    { label: '100-300', min: '100', max: '300' },
    { label: '300-500', min: '300', max: '500' },
    { label: '500以上', min: '500', max: '' },
  ],
  ratio: [
    { label: '0-20', min: '0', max: '20' },
    { label: '20-30', min: '20', max: '30' },
    { label: '30-40', min: '30', max: '40' },
    { label: '40以上', min: '40', max: '' },
  ],
  deposit: [
    { label: '0-50', min: '0', max: '50' },
    { label: '50-100', min: '50', max: '100' },
    { label: '100-200', min: '100', max: '200' },
    { label: '200以上', min: '200', max: '' },
  ],
  total: [
    { label: '0-500', min: '0', max: '500' },
    { label: '500-1000', min: '500', max: '1000' },
    { label: '1000-2000', min: '1000', max: '2000' },
    { label: '2000-5000', min: '2000', max: '5000' },
  ],
  fireLevel: [
    { label: '38-50', min: '38', max: '50' },
    { label: '50-60', min: '50', max: '60' },
    { label: '60-70', min: '60', max: '70' },
    { label: '70以上', min: '70', max: '' },
  ],
  resource_awmAmmo: [
    { label: '0-20', min: '0', max: '20' },
    { label: '20-50', min: '20', max: '50' },
    { label: '50-100', min: '50', max: '100' },
    { label: '100-200', min: '100', max: '200' },
    { label: '200以上', min: '200', max: '' },
  ],
}

const activeSortLabel = computed(
  () => sortOptions.find(option => option.key === activeSort.value)?.label || '综合排序'
)

async function handleSupportClick() {
  if (!session.isLoggedIn) {
    router.push({ path: '/m/login', query: { redirect: router.currentRoute.value.fullPath } })
    return
  }
  if (supportLoading.value) return
  supportLoading.value = true
  try {
    const scene = resolveSupportScene(route.path)
    const chat = await ensureSupportChat(scene)
    router.push(`/m/chats/${chat.id}`)
  } catch {
    showToast({ message: '联系客服失败，请稍后重试', icon: 'cross' })
  } finally {
    supportLoading.value = false
  }
}

const serverFilterOptions = computed(() =>
  uniqueOptions(publishOptions.value.server_options.map(item => item.trim()).filter(Boolean))
)

const loginMethodFilterOptions = computed(() =>
  uniqueOptions(publishOptions.value.login_method_options.map(item => item.trim()).filter(Boolean))
)

const regionFilterOptions = computed(() =>
  uniqueOptions([
    ...publishOptions.value.region_options,
    ...listings.value.flatMap(item => assetRegions(item)),
  ])
)

const filterSections = computed<FilterSection[]>(() => [
  {
    key: 'price',
    title: '价格区间',
    type: 'range',
    unit: '元',
    minPlaceholder: '最低价',
    maxPlaceholder: '最高价',
  },
  {
    key: 'coin',
    title: '哈夫币数量',
    type: 'range',
    unit: 'M',
    minPlaceholder: '最低',
    maxPlaceholder: '最高',
  },
  {
    key: 'ratio',
    title: '比例',
    type: 'range',
    unit: 'w/元',
    minPlaceholder: '最低比例',
    maxPlaceholder: '最高比例',
  },
  { key: 'server', title: '区服', type: 'chips', options: serverFilterOptions.value },
  { key: 'region', title: '资产地区', type: 'chips', options: regionFilterOptions.value },
  { key: 'login', title: '上号方式', type: 'chips', options: loginMethodFilterOptions.value },
  {
    key: 'insurance',
    title: '保险',
    type: 'chips',
    options: publishOptions.value.insurance_options,
  },
  { key: 'stamina', title: '体力', type: 'chips', options: publishOptions.value.level_options },
  { key: 'load', title: '负重', type: 'chips', options: publishOptions.value.level_options },
  ...publishOptions.value.quantity_items.map(item => ({
    key: `resource_${item.key}`,
    title: item.label,
    type: 'range' as const,
    unit: parseQuantityUnit(item.price),
    minPlaceholder: '最低',
    maxPlaceholder: '最高',
  })),
  ...publishOptions.value.skin_groups.map(group => ({
    key: group.key,
    title: group.title,
    type: 'chips' as const,
    options: group.options,
  })),
  {
    key: 'secretKd',
    title: '绝密KD',
    type: 'range',
    minPlaceholder: '最低',
    maxPlaceholder: '最高',
  },
  {
    key: 'fireLevel',
    title: '等级',
    type: 'range',
    minPlaceholder: '最低',
    maxPlaceholder: '最高',
  },
  { key: 'rank', title: '段位', type: 'chips', options: publishOptions.value.rank_options },
  {
    key: 'deposit',
    title: '押金',
    type: 'range',
    unit: '元',
    minPlaceholder: '最低',
    maxPlaceholder: '最高',
  },
  {
    key: 'total',
    title: '合计金额',
    type: 'range',
    unit: '元',
    minPlaceholder: '最低',
    maxPlaceholder: '最高',
  },
])

const activeFilterCount = computed(() => {
  const chipCount = Object.values(selectedFilters.value).reduce(
    (sum, values) => sum + values.length,
    0
  )
  const rangeCount = Object.values(rangeFilters.value).filter(
    range => range.min || range.max
  ).length
  return chipCount + rangeCount
})

const displayListings = computed(() => {
  return listings.value
})

const visibleZoneOptions = computed(() =>
  zoneOptions.map(zone => ({
    ...zone,
    count: zoneCount(zone.key),
  }))
)

applyRouteQueryToMobileState()

function currentListSignature() {
  return buildMobileHomeListSignature({
    searchValue: searchValue.value,
    activeSort: activeSort.value,
    activeZone: activeZone.value,
    selectedFilters: selectedFilters.value,
    rangeFilters: rangeFilters.value,
  })
}

function persistListCache() {
  homeCache.saveList({
    signature: currentListSignature(),
    listings: listings.value.slice(),
    totalListings: totalListings.value,
    zoneCounts: { ...zoneCounts.value },
    currentPage: currentPage.value,
    hasMoreListings: hasMoreListings.value,
  })
}

function persistScrollTop() {
  if (!scrollEl.value) return
  homeCache.saveScrollTop(scrollEl.value.scrollTop)
}

function restoreFromCache() {
  const signature = currentListSignature()
  if (!homeCache.matchList(signature)) return false
  // 拷贝快照，避免页面内变更直接写穿 store
  listings.value = homeCache.listings.slice()
  totalListings.value = homeCache.totalListings
  zoneCounts.value = { ...homeCache.zoneCounts }
  currentPage.value = homeCache.currentPage
  hasMoreListings.value = homeCache.hasMoreListings
  loadFailed.value = false
  loading.value = false
  loadingMore.value = false
  return true
}

function restoreHomeConfigFromCache() {
  if (!homeCache.homeConfigLoaded) return false
  announcements.value = homeCache.announcements.slice()
  bannerSlides.value = homeCache.bannerSlides.map(slide => ({ ...slide }))
  publishOptions.value = homeCache.publishOptions
  return true
}

function restoreScrollPosition() {
  const top = homeCache.scrollTop
  const apply = () => {
    if (scrollEl.value) scrollEl.value.scrollTop = top
  }
  apply()
  nextTick(() => {
    apply()
    requestAnimationFrame(() => {
      apply()
      requestAnimationFrame(() => {
        apply()
        handleListScroll()
      })
    })
  })
}

onMounted(() => {
  const restoredList = restoreFromCache()
  if (!restoredList) {
    loadListings()
  }
  if (!restoreHomeConfigFromCache()) {
    loadHomeConfig()
  }
  if (restoredList) {
    restoreScrollPosition()
  }
})

onBeforeRouteLeave(() => {
  persistScrollTop()
})

onBeforeUnmount(() => {
  persistScrollTop()
  if (searchDebounceTimer) clearTimeout(searchDebounceTimer)
})

watch(
  () => filterQuerySignature(),
  () => {
    // 筛选弹层打开时只改本地 state，避免每个按键写 URL/storage 后被旧缓存回写
    if (filterOpen.value) return
    applyFilterStateAndReload()
  }
)

watch(filterOpen, (open, wasOpen) => {
  // 关闭弹层时再统一同步 URL 并刷新列表
  if (wasOpen && !open) {
    applyFilterStateAndReload()
  }
})

watch(
  () => route.query,
  () => {
    applyRouteQueryToMobileState()
  }
)

watch(searchValue, () => {
  syncMobileHomeQuery()
  if (searchDebounceTimer) clearTimeout(searchDebounceTimer)
  searchDebounceTimer = setTimeout(() => {
    homeCache.clearList()
    loadListings(true)
  }, 300)
})

async function loadListings(reset = true) {
  if ((loadingMore.value && !reset) || (!hasMoreListings.value && !reset)) return
  const requestSeq = ++listingRequestSeq
  if (reset) {
    loading.value = true
    currentPage.value = 1
    hasMoreListings.value = true
  }
  loadingMore.value = true
  loadFailed.value = false
  try {
    const page = await fetchListingsPage(buildListingQuery(currentPage.value))
    if (requestSeq !== listingRequestSeq) return
    listings.value = reset ? page.items : [...listings.value, ...page.items]
    totalListings.value = page.total
    zoneCounts.value = page.zone_counts
    hasMoreListings.value = listings.value.length < page.total
    currentPage.value = page.page + 1
    persistListCache()
    if (reset) {
      homeCache.saveScrollTop(0)
      if (scrollEl.value) scrollEl.value.scrollTop = 0
    }
    requestAnimationFrame(handleListScroll)
  } catch {
    if (reset) {
      listings.value = []
      totalListings.value = 0
      zoneCounts.value = {}
      hasMoreListings.value = false
      loadFailed.value = true
      homeCache.clearList()
    }
  } finally {
    if (requestSeq === listingRequestSeq) {
      loading.value = false
      loadingMore.value = false
    }
  }
}

async function loadHomeConfig() {
  try {
    const config = await fetchMobileHomeConfig()
    announcements.value = config.announcements
    bannerSlides.value = config.banners
    awRecycle.value = config.aw_recycle
    cooperationFeedback.value = config.cooperation_feedback
    publishOptions.value = config.publish_options
    homeCache.saveHomeConfig({
      announcements: config.announcements,
      bannerSlides: config.banners,
      publishOptions: config.publish_options,
    })
  } catch {
    announcements.value = defaultHomeAnnouncements
    bannerSlides.value = defaultHomeBanners
    awRecycle.value = { ...defaultAWRecycleConfig }
    cooperationFeedback.value = { ...defaultCooperationFeedbackConfig }
    publishOptions.value = emptyListingPublishOptions
  }
}

function openAWRecycle() {
  if (!awRecycle.value.image_url) {
    showToast({ message: '回收说明图片尚未配置', icon: 'warning-o' })
    return
  }
  awRecyclePreviewVisible.value = true
}

function openCooperationFeedback() {
  if (!cooperationFeedback.value.image_url) {
    showToast({ message: '合作与反馈图片尚未配置', icon: 'warning-o' })
    return
  }
  cooperationFeedbackPreviewVisible.value = true
}

function openBannerPreview(slide: HomeBannerSlide) {
  const url = slide.image_url?.trim()
  if (!url) return
  const images = bannerSlides.value
    .map(item => item.image_url?.trim() || '')
    .filter((item): item is string => Boolean(item))
  const startPosition = images.indexOf(url)
  if (startPosition < 0) return
  showImagePreview({
    images,
    startPosition,
    closeable: true,
  })
}

function hasBannerCopy(slide: HomeBannerSlide) {
  return Boolean(slide.eyebrow?.trim() || slide.title?.trim() || slide.pill?.trim())
}

async function onRefresh() {
  refreshing.value = true
  try {
    homeCache.clearList()
    const [, nextHomeConfig] = await Promise.all([loadListings(true), fetchMobileHomeConfig()])
    announcements.value = nextHomeConfig.announcements
    bannerSlides.value = nextHomeConfig.banners
    awRecycle.value = nextHomeConfig.aw_recycle
    cooperationFeedback.value = nextHomeConfig.cooperation_feedback
    publishOptions.value = nextHomeConfig.publish_options
    homeCache.saveHomeConfig({
      announcements: nextHomeConfig.announcements,
      bannerSlides: nextHomeConfig.banners,
      publishOptions: nextHomeConfig.publish_options,
    })
    showToast({ message: '刷新成功', icon: 'passed' })
  } catch {
    // 静默处理
  } finally {
    refreshing.value = false
  }
}

function openFilters() {
  sortOpen.value = false
  filterOpen.value = true
}

function toggleSortPanel() {
  sortOpen.value = !sortOpen.value
}

function selectSort(sortKey: string) {
  activeSort.value = sortKey
  sortOpen.value = false
}

function selectZone(zoneKey: string) {
  activeZone.value = zoneKey
  sortOpen.value = false
}

function clearFilters() {
  clearStoredHomeQuery(mobileHomeFilterStorageKey)
  selectedFilters.value = {}
  rangeFilters.value = {}
  searchValue.value = ''
  activeZone.value = 'all'
  syncMobileHomeQuery()
}

function buildListingQuery(page: number): PublicListingQuery {
  const query: PublicListingQuery = {
    page,
    page_size: mobilePageSize,
    keyword: searchValue.value.trim(),
    sort: activeSort.value,
    zone: activeZone.value,
  }
  const skinGroups: string[] = []
  const skinNames: string[] = []
  for (const [key, values] of Object.entries(selectedFilters.value)) {
    const value = values.filter(Boolean).join(',')
    if (!value) continue
    if (key === 'server') query.server = value
    else if (key === 'region') query.region = value
    else if (key === 'login') query.login_method = value
    else if (key === 'insurance') query.insurance = value
    else if (key === 'stamina') query.stamina = value
    else if (key === 'load') query.load = value
    else if (key === 'rank') query.rank = value
    else if (isSkinGroupKey(key)) {
      skinGroups.push(key)
      skinNames.push(...values)
    }
  }
  if (skinGroups.length) query.skin_group = skinGroups.join(',')
  if (skinNames.length) query.skin_name = skinNames.join(',')

  for (const [key, range] of Object.entries(rangeFilters.value)) {
    if (!range.min && !range.max) continue
    const min = parseOptionalNumber(range.min)
    const max = parseOptionalNumber(range.max)
    if (key === 'price') {
      query.min_price = min
      query.max_price = max
    } else if (key === 'coin') {
      query.min_coin = min
      query.max_coin = max
    } else if (key === 'ratio') {
      query.min_ratio = min
      query.max_ratio = max
    } else if (key === 'secretKd') {
      query.min_secret_kd = min
      query.max_secret_kd = max
    } else if (key === 'deposit') {
      query.min_deposit = min
      query.max_deposit = max
    } else if (key === 'total') {
      query.min_total = min
      query.max_total = max
    } else if (key === 'fireLevel') {
      query.min_fire_level = min
      query.max_fire_level = max
    } else if (key.startsWith('resource_')) {
      const resourceKey = key.replace('resource_', '')
      query[`resource_${resourceKey}_min`] = min
      query[`resource_${resourceKey}_max`] = max
    }
  }
  return query
}

function filterQuerySignature() {
  return JSON.stringify({
    sort: activeSort.value,
    zone: activeZone.value,
    selected: selectedFilters.value,
    ranges: rangeFilters.value,
  })
}

function parseOptionalNumber(value: string) {
  if (value === '') return undefined
  const number = Number(value)
  return Number.isFinite(number) ? number : undefined
}

function applyRouteQueryToMobileState() {
  const storedQuery = readStoredHomeQuery(mobileHomeFilterStorageKey)
  const query = hasHomeQueryValues(route.query, mobileHomeFilterQueryKeys)
    ? route.query
    : storedQuery
  const nextSearch = readQueryString(query, 'keyword')
  const nextSort = readQueryString(query, 'sort') || 'recommended'
  const nextZone = readQueryString(query, 'zone') || 'all'
  const nextFilters = normalizeSelectedFilters(
    decodeHomeQueryJson<Record<string, unknown>>(query, 'filters', {})
  )
  const nextRanges = normalizeRangeFilters(
    decodeHomeQueryJson<Record<string, unknown>>(query, 'ranges', {})
  )

  // 内容未变时避免赋值，防止 URL 回写时误触发列表刷新
  if (
    searchValue.value === nextSearch &&
    activeSort.value === nextSort &&
    activeZone.value === nextZone &&
    JSON.stringify(selectedFilters.value) === JSON.stringify(nextFilters) &&
    JSON.stringify(rangeFilters.value) === JSON.stringify(nextRanges)
  ) {
    return
  }

  searchValue.value = nextSearch
  activeSort.value = nextSort
  activeZone.value = nextZone
  selectedFilters.value = nextFilters
  rangeFilters.value = nextRanges
}

function applyFilterStateAndReload() {
  syncMobileHomeQuery()
  // 筛选变化时清空旧列表缓存，避免返回时命中过期数据
  homeCache.clearList()
  loadListings(true)
}

function syncMobileHomeQuery() {
  const query = mergeHomeQuery(route.query, mobileHomeFilterQueryKeys, buildMobileHomeQueryValues())
  if (hasHomeQueryValues(query, mobileHomeFilterQueryKeys)) {
    storeHomeQuery(mobileHomeFilterStorageKey, query)
  } else {
    // 筛选被清空时必须清掉 storage，否则 URL 变空会回退读出旧区间（最后一位删不掉）
    clearStoredHomeQuery(mobileHomeFilterStorageKey)
  }
  if (isSameQuery(route.query, query)) return
  router.replace({ path: route.path, query })
}

function buildMobileHomeQueryValues(): Record<string, HomeQueryValue> {
  return {
    keyword: searchValue.value.trim() || undefined,
    sort: activeSort.value === 'recommended' ? undefined : activeSort.value,
    zone: activeZone.value === 'all' ? undefined : activeZone.value,
    filters: encodeHomeQueryJson(normalizeSelectedFilters(selectedFilters.value)),
    ranges: encodeHomeQueryJson(normalizeRangeFilters(rangeFilters.value)),
  }
}

function normalizeSelectedFilters(value: Record<string, unknown>) {
  const normalized: Record<string, string[]> = {}
  for (const [key, items] of Object.entries(value)) {
    if (!Array.isArray(items)) continue
    const filters = items.map(item => String(item).trim()).filter(Boolean)
    if (filters.length) normalized[key] = filters
  }
  return normalized
}

function normalizeRangeFilters(value: Record<string, unknown>) {
  const normalized: Record<string, { min: string; max: string }> = {}
  for (const [key, range] of Object.entries(value)) {
    if (!range || typeof range !== 'object' || Array.isArray(range)) continue
    const record = range as Record<string, unknown>
    const min = record.min === undefined ? '' : String(record.min).trim()
    const max = record.max === undefined ? '' : String(record.max).trim()
    if (min || max) normalized[key] = { min, max }
  }
  return normalized
}

function handleListScroll() {
  const el = scrollEl.value
  if (!el) return
  homeCache.saveScrollTop(el.scrollTop)
  showBackTop.value = el.scrollTop > 520
  if (el.scrollTop + el.clientHeight < el.scrollHeight - 360) return
  loadListings(false)
}

function scrollToTop() {
  scrollEl.value?.scrollTo({ top: 0, behavior: 'smooth' })
  homeCache.saveScrollTop(0)
}

function isSkinGroupKey(key: string) {
  return publishOptions.value.skin_groups.some(group => group.key === key)
}

function parseQuantityUnit(price: string) {
  const unit = price.split('/')[1]?.trim()
  return unit || undefined
}

function uniqueOptions(values: string[]) {
  return [...new Set(values.map(item => item.trim()).filter(Boolean))]
}

function zoneCount(key: string) {
  if (key === 'all') return zoneCounts.value.all ?? totalListings.value
  return zoneCounts.value[key] ?? 0
}

function getAccessBadgeMeta(value: string) {
  const text = value.trim()
  if (text.includes('微信')) return { icon: 'wechat', tone: 'wechat' }
  if (text.toUpperCase().includes('QQ')) return { icon: 'qq', tone: 'qq' }
  if (text.includes('扫码')) return { icon: 'scan', tone: 'scan' }
  if (text.includes('账号') || text.includes('密码')) return { icon: 'lock', tone: 'password' }
  if (text.includes('Steam')) return { icon: 'desktop-o', tone: 'steam' }
  return { icon: 'bookmark-o', tone: 'default' }
}

function getMobileRatioText(item: Listing) {
  const ratio = getRatioValue(item)
  if (ratio <= 0) return ''
  const formatted = Number.isInteger(ratio) ? String(ratio) : ratio.toFixed(1)
  return `1元=${formatted}w哈夫币`
}

function chipTone(label: string) {
  if (label.includes('哈夫币')) return 'coin'
  if (label.includes('保险')) return 'insurance'
  if (label.includes('体力')) return 'stamina'
  if (label.includes('负重')) return 'load'
  if (label.includes('段位')) return 'rank'
  if (label.includes('AWM')) return 'weapon'
  if (label.includes('总资产')) return 'asset'
  if (label.includes('方便')) return 'time'
  return 'default'
}

syncMobileHomeQuery()
</script>

<template>
  <main class="mobile-shell">
    <div ref="scrollEl" class="mobile-scroll" @scroll.passive="handleListScroll">
      <!-- ========== Hero 区域：顶部搜索与公告 ========== -->
      <section class="mobile-hero">
        <div class="mobile-topbar">
          <div class="mobile-brand">
            <span class="mobile-logo">锤</span>
            <div>
              <strong>大锤商行</strong>
              <small>哈夫币租号</small>
            </div>
          </div>
          <button
            class="mobile-service"
            type="button"
            :disabled="supportLoading"
            @click="handleSupportClick"
          >
            {{ supportLoading ? '接入中' : '客服' }}
          </button>
        </div>
        <RouterLink
          class="add-home-strip"
          to="/m/add-home-guide"
          aria-label="查看添加到手机桌面教程"
        >
          <span class="add-home-mark">
            <van-icon name="home-o" :size="18" />
          </span>
          <span class="add-home-copy">
            <strong>添加到手机桌面</strong>
            <small>下次像 App 一样快速打开</small>
          </span>
          <span class="add-home-cta">去添加</span>
        </RouterLink>
        <van-search
          v-model="searchValue"
          shape="round"
          placeholder="搜编号 / 区服 / 段位"
          class="home-search"
        />

        <!-- 防骗提示卡片（不用 van-notice-bar） -->
        <RouterLink class="fraud-tip" to="/m/announcements">
          <van-icon name="warning-o" :size="16" color="#b8860b" />
          <span class="fraud-dot"></span>
          <van-swipe
            class="announcement-swipe"
            vertical
            :autoplay="3200"
            :show-indicators="false"
            touchable
          >
            <van-swipe-item v-for="item in announcements" :key="item">
              <span>{{ item }}</span>
            </van-swipe-item>
          </van-swipe>
          <van-icon class="fraud-more" name="arrow" :size="14" />
        </RouterLink>
      </section>

      <!-- ========== Content 区域 ========== -->
      <van-pull-refresh v-model="refreshing" @refresh="onRefresh">
        <section class="mobile-content">
          <!-- Banner 轮播 -->
          <van-swipe class="banner-swipe" :autoplay="3600" lazy-render>
            <van-swipe-item v-for="slide in bannerSlides" :key="slide.title || slide.image_url">
              <div
                class="mobile-banner"
                :class="[
                  `tone-${slide.tone}`,
                  {
                    'has-image': slide.image_url,
                    'has-copy': hasBannerCopy(slide),
                    'is-previewable': !!slide.image_url,
                  },
                ]"
                @click="openBannerPreview(slide)"
              >
                <img
                  v-if="slide.image_url"
                  class="banner-image"
                  :src="slide.image_url"
                  :alt="slide.title || slide.eyebrow || '首页轮播图'"
                />
                <div class="banner-copy">
                  <p v-if="slide.eyebrow">{{ slide.eyebrow }}</p>
                  <h1 v-if="slide.title">{{ slide.title }}</h1>
                  <span v-if="slide.pill" class="banner-pill">{{ slide.pill }}</span>
                </div>
                <div v-if="slide.badge" class="banner-badge">{{ slide.badge }}</div>
              </div>
            </van-swipe-item>
          </van-swipe>

          <div class="biz-entry-grid" aria-label="业务入口">
            <RouterLink class="biz-entry" to="/">
              <strong>租号大厅</strong>
              <small>高哈夫币 · 随租随玩</small>
            </RouterLink>
            <RouterLink class="biz-entry" to="/crash">
              <strong>撞车</strong>
              <small>选购商品 · 一键找客服</small>
              <em class="biz-entry-badge">NEW</em>
            </RouterLink>
            <button
              v-if="awRecycle.enabled"
              type="button"
              class="biz-entry aw-recycle"
              @click="openAWRecycle"
            >
              <strong>{{ awRecycle.title }}</strong>
              <small>{{ awRecycle.subtitle }}</small>
            </button>
            <button
              v-if="cooperationFeedback.enabled"
              type="button"
              class="biz-entry cooperation-feedback"
              @click="openCooperationFeedback"
            >
              <strong>{{ cooperationFeedback.title }}</strong>
              <small>{{ cooperationFeedback.subtitle }}</small>
            </button>
          </div>

          <div class="zone-strip" aria-label="账号专区">
            <button
              v-for="zone in visibleZoneOptions"
              :key="zone.key"
              type="button"
              class="zone-pill"
              :class="{ active: activeZone === zone.key }"
              @click="selectZone(zone.key)"
            >
              <strong>{{ zone.label }}</strong>
              <span>{{ zone.count }}</span>
              <small>{{ zone.hint }}</small>
            </button>
          </div>

          <div class="list-toolbar">
            <button type="button" class="sort-entry" @click="toggleSortPanel">
              <span>{{ activeSortLabel }}</span>
              <van-icon :name="sortOpen ? 'arrow-up' : 'arrow-down'" :size="14" />
            </button>
            <button type="button" class="filter-entry" @click="openFilters">
              <van-icon name="filter-o" :size="16" />
              <span>筛选</span>
              <em v-if="activeFilterCount">{{ activeFilterCount }}</em>
            </button>
          </div>
          <div v-if="sortOpen" class="sort-panel">
            <button
              v-for="option in sortOptions"
              :key="option.key"
              type="button"
              :class="{ active: activeSort === option.key }"
              @click="selectSort(option.key)"
            >
              <span>{{ option.label }}</span>
              <van-icon v-if="activeSort === option.key" name="success" :size="18" />
            </button>
          </div>
          <div class="result-count">
            <strong>{{ totalListings }}</strong>
            <span>个可租账号</span>
          </div>

          <!-- 加载/错误状态 -->
          <van-loading v-if="loading" class="state-loading" size="24px" vertical>
            正在加载优质账号...
          </van-loading>
          <van-notice-bar
            v-else-if="loadFailed"
            left-icon="info-o"
            color="#6b7a90"
            background="transparent"
            text="接口暂不可用，请稍后刷新。"
          />
          <van-empty
            v-else-if="displayListings.length === 0"
            class="mobile-empty"
            image="search"
            description="没有符合条件的账号"
          >
            <van-button size="small" type="primary" @click="clearFilters"> 重置条件 </van-button>
          </van-empty>

          <!-- 列表卡片：全宽上下布局 -->
          <div class="mobile-list">
            <RouterLink
              v-for="item in displayListings"
              :key="item.id"
              class="mobile-card"
              :to="`/m/listings/${item.id}`"
            >
              <div class="card-cover">
                <img
                  v-if="item.cover_url"
                  :src="item.cover_url"
                  :alt="getListingTitle(item)"
                  loading="lazy"
                  decoding="async"
                />
                <span v-else>图</span>
                <div
                  v-if="hasGiftResources(item) || hasAcceleratedSaleRatio(item)"
                  class="card-cover-labels"
                >
                  <em v-if="hasGiftResources(item)">有赠送</em>
                  <em v-if="hasAcceleratedSaleRatio(item)">特惠</em>
                </div>
              </div>
              <div class="card-main">
                <div class="card-title-row">
                  <h2>{{ getListingTitle(item) }}</h2>
                </div>
                <div class="card-meta-row">
                  <div class="mobile-listing-no">{{ formatListingCode(item) }}</div>
                  <div
                    v-if="getDailyLoss(item) || formatEstimatedRentalDuration(item) !== '--'"
                    class="rental-meta-badge"
                  >
                    <span v-if="getDailyLoss(item)">消耗 {{ getDailyLoss(item) }}/天</span>
                    <span
                      v-if="getDailyLoss(item) && formatEstimatedRentalDuration(item) !== '--'"
                      class="meta-separator"
                    >
                      ·
                    </span>
                    <span v-if="formatEstimatedRentalDuration(item) !== '--'">
                      租期 {{ formatEstimatedRentalDuration(item) }}
                    </span>
                  </div>
                </div>
                <div class="card-action-row">
                  <p v-if="getMobileRatioText(item)" class="card-subtitle">
                    {{ getMobileRatioText(item) }}
                  </p>
                  <div class="card-badges-row">
                    <span
                      class="server-badge"
                      :class="`tone-${getAccessBadgeMeta(getServerRegion(item)).tone}`"
                    >
                      <van-icon :name="getAccessBadgeMeta(getServerRegion(item)).icon" :size="13" />
                      {{ getServerRegion(item) }}
                    </span>
                    <span
                      v-if="getLoginMethod(item)"
                      class="server-badge"
                      :class="`tone-${getAccessBadgeMeta(getLoginMethod(item)).tone}`"
                    >
                      <van-icon :name="getAccessBadgeMeta(getLoginMethod(item)).icon" :size="13" />
                      {{ getLoginMethod(item) }}
                    </span>
                  </div>
                </div>
                <div class="card-footer">
                  <div class="price-col">
                    <strong>¥{{ formatMoney(getListingDisplayPrice(item)) }}</strong>
                    <span class="rent-sub">押金 ¥{{ formatCent(item.deposit_amount_cent) }}</span>
                  </div>
                </div>
              </div>
              <div class="card-chip-row">
                <span
                  v-for="chip in getListingChips(item)"
                  :key="`${item.id}-${chip.label}`"
                  :class="`tone-${chipTone(chip.label)}`"
                >
                  {{ chip.label }}:{{ chip.value }}
                </span>
              </div>
            </RouterLink>
          </div>
          <div v-if="!loading && displayListings.length" class="mobile-load-state">
            <span v-if="loadingMore">正在加载更多账号...</span>
            <span v-else-if="!hasMoreListings">已经到底了</span>
          </div>
        </section>
      </van-pull-refresh>

      <footer class="home-footer">
        <a
          href="https://beian.miit.gov.cn/"
          target="_blank"
          rel="noopener noreferrer"
          class="home-footer-icp"
          >湘ICP备2025146668号</a
        >
        <span class="home-footer-divider">|</span>
        <span class="home-footer-copyright">版权所有 ©2026 大锤网络游戏有限公司</span>
      </footer>
    </div>

    <MobileHomeFilterSheet
      v-model:show="filterOpen"
      v-model:selected-filters="selectedFilters"
      v-model:range-filters="rangeFilters"
      :sections="filterSections"
      :range-presets="rangePresets"
      @reset="clearFilters"
    />

    <button
      v-if="showBackTop"
      class="back-top-button"
      type="button"
      aria-label="回到顶部"
      @click="scrollToTop"
    >
      <van-icon name="arrow-up" :size="20" />
    </button>

    <van-popup
      v-model:show="awRecyclePreviewVisible"
      position="center"
      round
      closeable
      teleport="body"
      class="aw-recycle-popup"
      :style="{ width: 'min(92vw, 420px)', maxHeight: '86vh' }"
    >
      <div class="aw-recycle-preview">
        <header class="aw-recycle-preview-head">
          <h3>{{ awRecycle.title }}</h3>
        </header>
        <div class="aw-recycle-preview-body">
          <AuthImage
            v-if="awRecycle.image_url"
            :source="awRecycle.image_url"
            :alt="awRecycle.title"
            fit="contain"
            image-class="aw-recycle-preview-img"
          />
          <van-empty v-else description="暂无展示图片" />
        </div>
      </div>
    </van-popup>

    <van-popup
      v-model:show="cooperationFeedbackPreviewVisible"
      position="center"
      round
      closeable
      teleport="body"
      class="aw-recycle-popup"
      :style="{ width: 'min(92vw, 420px)', maxHeight: '86vh' }"
    >
      <div class="aw-recycle-preview">
        <header class="aw-recycle-preview-head">
          <h3>{{ cooperationFeedback.title }}</h3>
        </header>
        <div class="aw-recycle-preview-body">
          <AuthImage
            v-if="cooperationFeedback.image_url"
            :source="cooperationFeedback.image_url"
            :alt="cooperationFeedback.title"
            fit="contain"
            image-class="aw-recycle-preview-img"
          />
          <van-empty v-else description="暂无展示图片" />
        </div>
      </div>
    </van-popup>

    <MobileBottomNav />
  </main>
</template>

<style scoped src="./MobileHomeView.css"></style>
