<template>
  <!-- 畜牧资源：参考养殖资讯 — 顶区搜索 + up-tabs（无右侧插槽、无 up-popup）；下区虚拟列表 -->
  <view :class="pageRootClass" class="tab-page lr-page" :style="pageStyle">
    <view class="lr-top">
      <up-search
        v-model="searchKeyword"
        shape="round"
        :placeholder="$t('livestockResourcesPage.searchPlaceholder')"
        :show-action="false"
        :clearabled="true"
        bg-color="#f5f2ef"
        border-color="#e5ded6"
      />
      <up-tabs
        :current="tabCurrentIndex"
        class="lr-tabs"
        :list="tabsList"
        key-name="name"
        :scrollable="false"
        line-color="#22C55E"
        :active-style="{ color: '#15803d', fontWeight: '600' }"
        :inactive-style="{ color: '#78716c' }"
        @update:current="tabCurrentIndex = $event"
        @change="onTabsChange"
      />
    </view>

    <view class="lr-body">
      <view v-if="listLoading && !articles.length" class="lr-empty">
        <text class="text-body lr-empty__txt">{{ $t('livestockResourcesPage.loading') }}</text>
      </view>
      <view v-else-if="!articles.length" class="lr-empty">
        <text class="text-body lr-empty__txt">{{ $t('livestockResourcesPage.empty') }}</text>
      </view>
      <view v-else class="lr-list-wrap">
        <up-virtual-list
          ref="lrVList"
          class="lr-vlist"
          :list-data="articles"
          :item-height="slotHeightPx"
          :height="listHeightPx"
          :buffer="6"
          key-field="id"
          :scroll-top="vScrollTop"
          @update:scrollTop="vScrollTop = $event"
          @scroll="onVirtualListScroll"
        >
          <template #default="{ item }">
            <view class="lr-row-cell">
              <view class="lr-row" :style="{ height: rowBodyPx + 'px' }">
                <view class="lr-row__left" role="button" @click="openResourceDetail(item)">
                  <text class="lr-row__title">{{ item.title }}</text>
                  <text class="text-body lr-row__summary">{{ item.introduction || $t('livestockResourcesPage.noIntro') }}</text>
                  <view class="lr-row__meta">
                    <text class="lr-row__meta-tag text-body">{{ tabTitle(item.type) }}</text>
                    <text class="lr-row__meta-date text-body">{{ item.publishTime || $t('livestockResourcesPage.noDate') }}</text>
                  </view>
                </view>
                <view class="lr-row__right">
                  <up-lazy-load
                    class="lr-lazy-cover"
                    role="button"
                    :image="articleCover(item)"
                    height="120"
                    :border-radius="12"
                    img-mode="aspectFill"
                    :threshold="200"
                    :index="item.id"
                    @click="() => onPreviewCover(item)"
                  />
                </view>
              </view>
            </view>
          </template>
        </up-virtual-list>
      </view>
    </view>
  </view>
</template>

<script>
import USearch from 'uview-plus/components/u-search/u-search.vue'
import UTabs from 'uview-plus/components/u-tabs/u-tabs.vue'
import ULazyLoad from 'uview-plus/components/u-lazy-load/u-lazy-load.vue'
import UVirtualList from 'uview-plus/components/u-virtual-list/u-virtual-list.vue'
import tabPage from '@/mixins/tabPage'
import { resolveResourceUrl } from '@/utils/resourceUrl'
import { listLivestockResource } from '@/api/livestockResource'

/** Tab 与资源类型编码（§1.2） */
const TAB_TYPE_CODES = ['004002', '004006', '004007', '004008']
const TAB_I18N_KEYS = ['t1', 't2', 't3', 't4']

/** 列表分页（接口默认 10，上限 50） */
const LIST_PAGE_SIZE = 20

const ROW_BODY_RPX = 260
const ROW_GAP_RPX = 20
/** lr-body 上下 padding（16 + 24 rpx） */
const LR_BODY_PAD_RPX = 40
const COVER = '/static/ai/hero.png'
const LIVESTOCK_DETAIL_PATH = '/package-a/livestock-resource-detail/index'

export default {
  components: {
    'up-search': USearch,
    'up-tabs': UTabs,
    'up-lazy-load': ULazyLoad,
    'up-virtual-list': UVirtualList
  },
  mixins: [tabPage],
  data() {
    return {
      navTitleKey: 'livestockResourcesPage.navTitle',
      searchKeyword: '',
      tabCurrentIndex: 0,
      articles: [],
      listLoading: false,
      listLoadingMore: false,
      listTotal: 0,
      pageNum: 1,
      pageSize: LIST_PAGE_SIZE,
      _searchTimer: null,
      loadMoreTimer: null,
      rowBodyPx: 120,
      marginPx: 10,
      slotHeightPx: 130,
      listHeightPx: 400,
      pageHeightPx: 0,
      lrTopHeightPx: 0,
      vScrollTop: 0,
      coverSrc: COVER
    }
  },
  computed: {
    tabsList() {
      return TAB_TYPE_CODES.map((code, i) => ({
        id: code,
        name: this.$t(`livestockResourcesPage.tabs.${TAB_I18N_KEYS[i]}`)
      }))
    },
    selectedTabId() {
      const row = this.tabsList[this.tabCurrentIndex]
      return row ? row.id : TAB_TYPE_CODES[0]
    },
    listNoMore() {
      return this.listTotal > 0 && this.articles.length >= this.listTotal
    },
    pageStyle() {
      if (this.pageHeightPx > 0) {
        return { height: `${this.pageHeightPx}px` }
      }
      return {}
    }
  },
  watch: {
    searchKeyword() {
      this.vScrollTop = 0
      clearTimeout(this._searchTimer)
      this._searchTimer = setTimeout(() => {
        this.loadResourceList(true)
      }, 300)
    },
    tabCurrentIndex() {
      this.vScrollTop = 0
      this.loadResourceList(true)
    }
  },
  created() {
    this.loadResourceList(true)
  },
  onReady() {
    try {
      this.marginPx = Math.ceil(uni.upx2px(ROW_GAP_RPX))
      this.rowBodyPx = Math.max(100, Math.ceil(uni.upx2px(ROW_BODY_RPX)))
      this.slotHeightPx = this.rowBodyPx + this.marginPx
    } catch (e) {
      this.marginPx = 10
      this.rowBodyPx = 120
      this.slotHeightPx = 130
    }
    this.applyListHeightFallback()
    this.$nextTick(() => this.calcLayoutHeights())
  },
  onShow() {
    this.$nextTick(() => this.calcLayoutHeights())
  },
  onUnload() {
    if (this.loadMoreTimer) clearTimeout(this.loadMoreTimer)
    if (this._searchTimer) clearTimeout(this._searchTimer)
  },
  methods: {
    mapResourceRow(row) {
      const resourceId = row.id
      const sourceType = row.sourceType
      const type = row.type || ''
      const publishTime = row.publishTime || ''
      const title = row.title || ''
      return {
        id: `${sourceType}-${resourceId}`,
        resourceId,
        sourceType,
        title,
        introduction: row.introduction || '',
        type,
        coverFileUrl: row.coverFileUrl || '',
        contentFileUrl: row.contentFileUrl || '',
        publishTime
      }
    },
    loadResourceList(reset = false) {
      const type = this.selectedTabId
      if (!type) {
        this.articles = []
        this.listTotal = 0
        return Promise.resolve()
      }
      if (!reset) {
        if (this.listLoading || this.listLoadingMore || this.listNoMore) {
          return Promise.resolve()
        }
        this.pageNum += 1
        this.listLoadingMore = true
      } else {
        this.pageNum = 1
        this.listLoading = true
      }
      const params = {
        type,
        pageNum: this.pageNum,
        pageSize: this.pageSize
      }
      const titleKw = (this.searchKeyword || '').trim()
      if (titleKw) {
        params.title = titleKw
      }
      return listLivestockResource(params)
        .then((res) => {
          const rows = res.rows || []
          this.listTotal = res.total != null ? Number(res.total) : 0
          const mapped = rows.map((row) => this.mapResourceRow(row))
          this.articles = reset ? mapped : this.articles.concat(mapped)
          this.$nextTick(() => {
            this.calcLayoutHeights()
            if (this.articles.length < this.listTotal) {
              this.tryAutoLoadMore()
            }
          })
        })
        .catch(() => {
          if (reset) {
            this.articles = []
            this.listTotal = 0
          } else {
            this.pageNum -= 1
          }
        })
        .finally(() => {
          if (reset) {
            this.listLoading = false
          } else {
            this.listLoadingMore = false
          }
        })
    },
    tryAutoLoadMore() {
      if (this.listLoading || this.listLoadingMore || this.listNoMore) return
      const totalH = this.articles.length * this.slotHeightPx
      const viewH = this.listHeightPx
      if (totalH > 0 && totalH <= viewH) {
        this.loadResourceList(false)
      }
    },
    onVirtualListScroll(scrollTop) {
      if (this.loadMoreTimer) clearTimeout(this.loadMoreTimer)
      this.loadMoreTimer = setTimeout(() => {
        this.loadMoreTimer = null
        this.tryLoadMoreOnScroll(typeof scrollTop === 'number' ? scrollTop : 0)
      }, 180)
    },
    tryLoadMoreOnScroll(scrollTop) {
      if (this.listLoading || this.listLoadingMore || this.listNoMore) return
      const totalH = this.articles.length * this.slotHeightPx
      const viewH = this.listHeightPx
      const threshold = Math.max(this.slotHeightPx * 2, 120)
      if (totalH <= viewH) {
        this.loadResourceList(false)
        return
      }
      if (scrollTop + viewH >= totalH - threshold) {
        this.loadResourceList(false)
      }
    },
    /** 系统导航栏高度（状态栏 + 标题栏） */
    getNavigationBarHeight() {
      const sys = uni.getSystemInfoSync()
      const statusBar = sys.statusBarHeight || 0
      // #ifdef MP-WEIXIN
      try {
        const menu = uni.getMenuButtonBoundingClientRect()
        if (menu && menu.height) {
          return statusBar + (menu.top - statusBar) * 2 + menu.height
        }
      } catch (e) {
        /* noop */
      }
      // #endif
      return statusBar + 44
    },
    /** 视口可用高度 = 屏幕高度 - 导航栏 */
    getViewportContentHeight() {
      const sys = uni.getSystemInfoSync()
      const navH = this.getNavigationBarHeight()
      // #ifdef H5
      if (typeof window !== 'undefined' && window.innerHeight) {
        return Math.max(320, window.innerHeight - navH)
      }
      // #endif
      const screenH = sys.screenHeight || sys.windowHeight || 600
      return Math.max(320, screenH - navH)
    },
    applyListHeightFallback() {
      const contentH = this.getViewportContentHeight()
      const lrTopFallback = Math.ceil(uni.upx2px(200))
      const bodyPad = Math.ceil(uni.upx2px(LR_BODY_PAD_RPX))
      this.pageHeightPx = contentH
      this.lrTopHeightPx = lrTopFallback
      this.listHeightPx = Math.max(240, contentH - lrTopFallback - bodyPad)
    },
    calcLayoutHeights() {
      const contentH = this.getViewportContentHeight()
      const bodyPad = Math.ceil(uni.upx2px(LR_BODY_PAD_RPX))
      this.pageHeightPx = contentH

      uni.createSelectorQuery()
        .in(this)
        .select('.lr-top')
        .boundingClientRect((topRect) => {
          const lrTopH =
            topRect && topRect.height > 0 ? Math.ceil(topRect.height) : Math.ceil(uni.upx2px(200))
          this.lrTopHeightPx = lrTopH
          // 列表高度 = 视口 - 导航栏(已扣) - lr-top - lr-body 内边距
          this.listHeightPx = Math.max(240, contentH - lrTopH - bodyPad)
          this.$nextTick(() => {
            this.$refs.lrVList?.measureContainerHeight?.()
          })
        })
        .exec()
    },
    tabTitle(typeCode) {
      const row = this.tabsList.find((t) => t.id === typeCode)
      return row ? row.name : String(typeCode || '')
    },
    articleCover(item) {
      if (item.coverFileUrl) {
        return resolveResourceUrl(item.coverFileUrl)
      }
      return this.coverSrc
    },
    onPreviewCover(item) {
      const url = this.articleCover(item)
      if (!url) return
      uni.previewImage({ urls: [url], current: 0 })
    },
    openResourceDetail(item) {
      if (!item || item.resourceId == null || !item.sourceType) {
        uni.showToast({ title: this.$t('livestockResourceDetailPage.invalidParams'), icon: 'none' })
        return
      }
      const q = [
        `id=${encodeURIComponent(String(item.resourceId))}`,
        `sourceType=${encodeURIComponent(String(item.sourceType))}`,
        `typeCode=${encodeURIComponent(item.type || '')}`
      ].join('&')
      uni.navigateTo({ url: `${LIVESTOCK_DETAIL_PATH}?${q}` })
    },
    onTabsChange(_item, index) {
      this.tabCurrentIndex = typeof index === 'number' ? index : this.tabCurrentIndex
    }
  }
}
</script>

<style lang="scss" scoped>
@import '@/styles/morandi.scss';
@import '@/styles/tab-page.scss';

.lr-page {
  display: flex;
  flex-direction: column;
  min-width: 0;
  width: 100%;
  height: 100%;
  min-height: 100%;
  overflow: hidden;
  box-sizing: border-box;
  background: $morandi-bg-page;
}

.lr-top {
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  gap: 20rpx;
  min-width: 0;
  padding: 20rpx 24rpx 16rpx;
  box-sizing: border-box;
  background: $morandi-bg-page;
  border-bottom: 1rpx solid $morandi-border-soft;
}

.lr-tabs {
  width: 100%;
  min-width: 0;
}

.lr-body {
  flex: 1;
  min-height: 0;
  height: 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  padding: 16rpx 24rpx 24rpx;
  box-sizing: border-box;
  overflow: hidden;
}

.lr-list-wrap {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.lr-vlist {
  flex: 1;
  min-height: 0;
  width: 100%;
  height: 100%;
}

.lr-empty {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 0;
  padding: 48rpx 24rpx;
  box-sizing: border-box;
}

.lr-empty__txt {
  color: $morandi-text-muted;
  text-align: center;
}

.lr-row-cell {
  height: 100%;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
}

.lr-row {
  display: flex;
  flex-direction: row;
  align-items: stretch;
  gap: 20rpx;
  min-width: 0;
  padding: 20rpx;
  box-sizing: border-box;
  border-radius: 16rpx;
  background: $morandi-bg-card;
  border: 1rpx solid $morandi-border;
  flex-shrink: 0;
}

.lr-row__left {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 12rpx;
}

.lr-row__title {
  font-size: 32rpx;
  font-weight: 600;
  line-height: 1.45;
  color: $morandi-text;
  word-break: break-word;
  overflow-wrap: anywhere;
}

.lr-row__summary {
  font-size: 24rpx;
  line-height: 1.55;
  color: $morandi-text-secondary;
  word-break: break-word;
  overflow-wrap: anywhere;
}

.lr-row__meta {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
  gap: 12rpx 20rpx;
  min-width: 0;
}

.lr-row__meta-tag {
  font-size: 22rpx;
  color: $morandi-accent-soft;
}

.lr-row__meta-date {
  font-size: 22rpx;
  color: $morandi-text-soft;
}

.lr-row__right {
  flex-shrink: 0;
  align-self: center;
  width: 160rpx;
  min-width: 0;
}

.lr-lazy-cover {
  width: 100%;
  display: block;
}

.lr-page.lang-bo {
  .lr-row__title {
    font-size: 30rpx;
    line-height: 1.75;
    letter-spacing: 2rpx;
    font-family: 'Noto Sans Tibetan', 'PingFang SC', 'Microsoft YaHei', sans-serif;
  }

  .lr-row__summary {
    font-size: 22rpx;
    line-height: 1.75;
    letter-spacing: 2rpx;
    font-family: 'Noto Sans Tibetan', 'PingFang SC', 'Microsoft YaHei', sans-serif;
  }

  .lr-row__meta-tag,
  .lr-row__meta-date {
    font-size: 20rpx;
    line-height: 1.75;
    letter-spacing: 2rpx;
    font-family: 'Noto Sans Tibetan', 'PingFang SC', 'Microsoft YaHei', sans-serif;
  }
}
</style>
