<template>
  <!-- 农技课堂：上区搜索 + 主 Tab + 子类 Chip；下区虚拟列表，每行两列卡片（视频课程 / 实战培训 底部样式不同） -->
  <view :class="pageRootClass" class="tab-page ac-page" :style="pageStyle">
    <view class="ac-top">
      <up-search
        v-model="searchKeyword"
        shape="round"
        :placeholder="$t('agriClassroomPage.searchPlaceholder')"
        :show-action="false"
        :clearabled="true"
        bg-color="#f5f2ef"
        border-color="#e5ded6"
      />
      <up-tabs
        :current="mainTabIndex"
        class="ac-tabs"
        :list="mainTabsList"
        key-name="name"
        :scrollable="false"
        line-color="#22C55E"
        :active-style="{ color: '#15803d', fontWeight: '600' }"
        :inactive-style="{ color: '#78716c' }"
        @update:current="onMainTabUpdate"
      />
      <!-- 第三行：子类 Chip，圆角线框；未选中灰，选中绿框绿字 -->
      <view class="ac-chips" role="tablist">
        <view
          v-for="code in subTypeCodes"
          :key="code"
          class="ac-chip"
          :class="{ 'ac-chip--on': chipSelected(code) }"
          role="button"
          @click="onPickSub(code)"
        >
          <text class="text-body ac-chip__txt">{{ subLabel(code) }}</text>
        </view>
      </view>
    </view>

    <view class="ac-body">
      <view v-if="listLoading && !pairedRows.length" class="ac-empty">
        <text class="text-body ac-empty__txt">{{ $t('agriClassroomPage.loading') }}</text>
      </view>
      <view v-else-if="!pairedRows.length" class="ac-empty">
        <text class="text-body ac-empty__txt">{{ $t('agriClassroomPage.empty') }}</text>
      </view>
      <view v-else class="ac-list-wrap">
        <up-virtual-list
          ref="acVList"
          class="ac-vlist"
          :list-data="pairedRows"
          :item-height="slotHeightPx"
          :height="listHeightPx"
          :buffer="4"
          key-field="id"
          :scroll-top="vScrollTop"
          @update:scrollTop="vScrollTop = $event"
          @scroll="onVirtualListScroll"
        >
        <template #default="{ item }">
          <view class="ac-pair-cell">
            <view class="ac-pair" :style="{ height: rowBodyPx + 'px' }">
              <view class="ac-pair__col">
                <view v-if="item.left" class="ac-card" role="button" @click="openCourseDetail(item.left)">
                  <up-lazy-load
                    class="ac-card__img"
                    :image="articleCover(item.left)"
                    height="120"
                    :border-radius="12"
                    img-mode="aspectFill"
                    :threshold="200"
                    :index="item.left.id"
                    @click.stop="() => onPreviewCover(item.left)"
                  />
                  <text class="ac-card__title">{{ item.left.title }}</text>
                    <view v-if="item.left.type === 'video'" class="ac-card__foot ac-card__foot--video">
                    <text class="text-body ac-card__meta">{{ videoSubLabel(item.left.typeCode) }}</text>
                    <text class="text-body ac-card__meta ac-card__meta--muted">{{ item.left.publishTime || $t('agriClassroomPage.noDate') }}</text>
                  </view>
                  <view v-else class="ac-card__foot ac-card__foot--train">
                    <text class="text-body ac-card__meta">{{ trainingSubLabel(item.left.typeCode) }}</text>
                    <up-icon name="account-fill" color="#22C55E" :size="16" />
                    <text class="text-body ac-card__meta ac-card__meta--num">
                      {{ item.left.enrolled }}/{{ item.left.total }}
                    </text>
                  </view>
                </view>
              </view>
              <view class="ac-pair__col">
                <view v-if="item.right" class="ac-card" role="button" @click="openCourseDetail(item.right)">
                  <up-lazy-load
                    class="ac-card__img"
                    :image="articleCover(item.right)"
                    height="120"
                    :border-radius="12"
                    img-mode="aspectFill"
                    :threshold="200"
                    :index="item.right.id"
                    @click.stop="() => onPreviewCover(item.right)"
                  />
                  <text class="ac-card__title">{{ item.right.title }}</text>
                  <view v-if="item.right.type === 'video'" class="ac-card__foot ac-card__foot--video">
                    <text class="text-body ac-card__meta">{{ videoSubLabel(item.right.typeCode) }}</text>
                    <text class="text-body ac-card__meta ac-card__meta--muted">{{ item.right.publishTime || $t('agriClassroomPage.noDate') }}</text>
                  </view>
                  <view v-else class="ac-card__foot ac-card__foot--train">
                    <text class="text-body ac-card__meta">{{ trainingSubLabel(item.right.typeCode) }}</text>
                    <up-icon name="account-fill" color="#22C55E" :size="16" />
                    <text class="text-body ac-card__meta ac-card__meta--num">
                      {{ item.right.enrolled }}/{{ item.right.total }}
                    </text>
                  </view>
                </view>
              </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 UIcon from 'uview-plus/components/u-icon/u-icon.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 { listAgriculturalCourse } from '@/api/agriculturalCourse'

/** 视频课程 course_topic（005001–005004） */
const VIDEO_TYPE_CODES = ['005001', '005002', '005003', '005004']
/** 实战培训 training_status（006001–006004） */
const TRAINING_TYPE_CODES = ['006001', '006002', '006003', '006004']

const LIST_PAGE_SIZE = 20
const ROW_BODY_RPX = 320
const ROW_GAP_RPX = 20
const AC_BODY_PAD_RPX = 40
const COVER = '/static/ai/hero.png'
/** 视频课程详情 */
const COURSE_DETAIL_PATH = '/package-a/course-detail/index'
/** 实战培训详情（英文路径） */
const TRAINING_DETAIL_PATH = '/package-a/training-detail/index'

export default {
  components: {
    'up-search': USearch,
    'up-tabs': UTabs,
    'up-icon': UIcon,
    'up-lazy-load': ULazyLoad,
    'up-virtual-list': UVirtualList
  },
  mixins: [tabPage],
  data() {
    return {
      navTitleKey: 'agriClassroomPage.navTitle',
      searchKeyword: '',
      /** 0 视频课程 1 实战培训 */
      mainTabIndex: 0,
      selectedVideoType: '005001',
      selectedTrainingType: '006002',
      allCards: [],
      listLoading: false,
      listLoadingMore: false,
      listTotal: 0,
      pageNum: 1,
      pageSize: LIST_PAGE_SIZE,
      _searchTimer: null,
      loadMoreTimer: null,
      rowBodyPx: 140,
      marginPx: 10,
      slotHeightPx: 150,
      listHeightPx: 400,
      pageHeightPx: 0,
      vScrollTop: 0,
      coverSrc: COVER
    }
  },
  computed: {
    mainTabsList() {
      return [
        { name: this.$t('agriClassroomPage.mainVideo'), id: 'video' },
        { name: this.$t('agriClassroomPage.mainTraining'), id: 'training' }
      ]
    },
    isVideoMain() {
      return this.mainTabIndex === 0
    },
    subTypeCodes() {
      return this.isVideoMain ? VIDEO_TYPE_CODES : TRAINING_TYPE_CODES
    },
    selectedTypeCode() {
      return this.isVideoMain ? this.selectedVideoType : this.selectedTrainingType
    },
    listNoMore() {
      return this.listTotal > 0 && this.allCards.length >= this.listTotal
    },
    pageStyle() {
      if (this.pageHeightPx > 0) {
        return { height: `${this.pageHeightPx}px` }
      }
      return {}
    },
    /** 虚拟列表每行 2 个卡片 */
    pairedRows() {
      const cards = this.allCards
      const rows = []
      for (let i = 0; i < cards.length; i += 2) {
        const L = cards[i]
        const R = cards[i + 1] || null
        rows.push({
          id: `${L.id}_${R ? R.id : 'x'}`,
          left: L,
          right: R
        })
      }
      return rows
    }
  },
  watch: {
    searchKeyword() {
      this.vScrollTop = 0
      clearTimeout(this._searchTimer)
      this._searchTimer = setTimeout(() => {
        this.loadCourseList(true)
      }, 300)
    },
    selectedVideoType() {
      if (this.isVideoMain) {
        this.vScrollTop = 0
        this.loadCourseList(true)
      }
    },
    selectedTrainingType() {
      if (!this.isVideoMain) {
        this.vScrollTop = 0
        this.loadCourseList(true)
      }
    }
  },
  created() {
    this.loadCourseList(true)
  },
  onReady() {
    try {
      this.marginPx = Math.ceil(uni.upx2px(ROW_GAP_RPX))
      this.rowBodyPx = Math.max(120, Math.ceil(uni.upx2px(ROW_BODY_RPX)))
      this.slotHeightPx = this.rowBodyPx + this.marginPx
    } catch (e) {
      this.marginPx = 10
      this.rowBodyPx = 140
      this.slotHeightPx = 150
    }
    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: {
    isTrainingType(typeCode) {
      return String(typeCode || '').startsWith('006')
    },
    mapCourseRow(row) {
      const typeCode = row.type || ''
      const isTraining = this.isTrainingType(typeCode)
      return {
        id: String(row.id != null ? row.id : ''),
        type: isTraining ? 'training' : 'video',
        typeCode,
        title: row.title || '',
        introduction: row.introduction || '',
        coverFileUrl: row.coverFileUrl || '',
        contentFileUrl: row.contentFileUrl || '',
        publishTime: row.publishTime || '',
        enrolled: row.actualEnrolledCount != null ? Number(row.actualEnrolledCount) : 0,
        total: row.plannedHeadCount != null ? Number(row.plannedHeadCount) : 0,
        registrationStartTime: row.registrationStartTime || '',
        registrationEndTime: row.registrationEndTime || '',
        trainingTime: row.trainingTime || '',
        expectedOutcome: row.expectedOutcome || ''
      }
    },
    loadCourseList(reset = false) {
      const type = this.selectedTypeCode
      if (!type) {
        this.allCards = []
        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 listAgriculturalCourse(params)
        .then((res) => {
          const rows = res.rows || []
          this.listTotal = res.total != null ? Number(res.total) : 0
          const mapped = rows.map((row) => this.mapCourseRow(row))
          this.allCards = reset ? mapped : this.allCards.concat(mapped)
          this.$nextTick(() => {
            this.calcLayoutHeights()
            if (this.allCards.length < this.listTotal) {
              this.tryAutoLoadMore()
            }
          })
        })
        .catch(() => {
          if (reset) {
            this.allCards = []
            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.pairedRows.length * this.slotHeightPx
      const viewH = this.listHeightPx
      if (totalH > 0 && totalH <= viewH) {
        this.loadCourseList(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.pairedRows.length * this.slotHeightPx
      const viewH = this.listHeightPx
      const threshold = Math.max(this.slotHeightPx * 2, 120)
      if (totalH <= viewH) {
        this.loadCourseList(false)
        return
      }
      if (scrollTop + viewH >= totalH - threshold) {
        this.loadCourseList(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 topFallback = Math.ceil(uni.upx2px(280))
      const bodyPad = Math.ceil(uni.upx2px(AC_BODY_PAD_RPX))
      this.pageHeightPx = contentH
      this.listHeightPx = Math.max(240, contentH - topFallback - bodyPad)
    },
    calcLayoutHeights() {
      const contentH = this.getViewportContentHeight()
      const bodyPad = Math.ceil(uni.upx2px(AC_BODY_PAD_RPX))
      this.pageHeightPx = contentH

      uni.createSelectorQuery()
        .in(this)
        .select('.ac-top')
        .boundingClientRect((topRect) => {
          const acTopH =
            topRect && topRect.height > 0 ? Math.ceil(topRect.height) : Math.ceil(uni.upx2px(280))
          this.listHeightPx = Math.max(240, contentH - acTopH - bodyPad)
          this.$nextTick(() => {
            this.$refs.acVList?.measureContainerHeight?.()
          })
        })
        .exec()
    },
    subLabel(typeCode) {
      return this.isVideoMain ? this.videoSubLabel(typeCode) : this.trainingSubLabel(typeCode)
    },
    chipSelected(typeCode) {
      return this.selectedTypeCode === typeCode
    },
    onPickSub(typeCode) {
      if (this.isVideoMain) {
        this.selectedVideoType = typeCode
      } else {
        this.selectedTrainingType = typeCode
      }
    },
    typeCodeIndex(typeCode, codes) {
      const idx = codes.indexOf(typeCode)
      return idx >= 0 ? idx : 0
    },
    videoSubLabel(typeCode) {
      const idx = this.typeCodeIndex(typeCode, VIDEO_TYPE_CODES)
      return this.$t(`agriClassroomPage.videoSubs.s${idx}`)
    },
    trainingSubLabel(typeCode) {
      const idx = this.typeCodeIndex(typeCode, TRAINING_TYPE_CODES)
      return this.$t(`agriClassroomPage.trainingSubs.s${idx}`)
    },
    articleCover(card) {
      if (card.coverFileUrl) {
        return resolveResourceUrl(card.coverFileUrl)
      }
      return this.coverSrc
    },
    onPreviewCover(card) {
      const url = this.articleCover(card)
      if (!url) return
      uni.previewImage({ urls: [url], current: 0 })
    },
    openCourseDetail(card) {
      if (!card) return
      if (card.type === 'training') {
        const q = [
          `id=${encodeURIComponent(card.id)}`,
          `date=${encodeURIComponent(card.publishTime || '')}`,
          `title=${encodeURIComponent(card.title || '')}`,
          `type=${encodeURIComponent(card.typeCode || '')}`,
          `enrolled=${encodeURIComponent(card.enrolled)}`,
          `total=${encodeURIComponent(card.total)}`,
          `introduction=${encodeURIComponent(card.introduction || '')}`,
          `trainingTime=${encodeURIComponent(card.trainingTime || '')}`,
          `expectedOutcome=${encodeURIComponent(card.expectedOutcome || '')}`,
          `cover=${encodeURIComponent(card.coverFileUrl || '')}`,
          `regStart=${encodeURIComponent(card.registrationStartTime || '')}`,
          `regEnd=${encodeURIComponent(card.registrationEndTime || '')}`
        ].join('&')
        uni.navigateTo({ url: `${TRAINING_DETAIL_PATH}?${q}` })
        return
      }
      const q = [
        `id=${encodeURIComponent(card.id)}`,
        `date=${encodeURIComponent(card.publishTime || '')}`,
        `title=${encodeURIComponent(card.title || '')}`,
        `type=${encodeURIComponent(card.typeCode || '')}`,
        `introduction=${encodeURIComponent(card.introduction || '')}`,
        `src=${encodeURIComponent(card.contentFileUrl || '')}`,
        `cover=${encodeURIComponent(card.coverFileUrl || '')}`,
        'mode=video'
      ].join('&')
      uni.navigateTo({ url: `${COURSE_DETAIL_PATH}?${q}` })
    },
    /** 主 Tab 切换：恢复各 Tab 默认子类并重新拉列表 */
    onMainTabUpdate(idx) {
      const i = typeof idx === 'number' ? idx : 0
      if (this.mainTabIndex === i) return
      this.mainTabIndex = i
      this.vScrollTop = 0
      if (i === 0) {
        this.selectedVideoType = '005001'
      } else {
        this.selectedTrainingType = '006002'
      }
      this.loadCourseList(true)
    }
  }
}
</script>

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

.ac-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;
}

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

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

.ac-chips {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  min-width: 0;
  justify-content: space-between;
}

.ac-chip {
  padding: 2rpx 30rpx;
  box-sizing: border-box;
  border-radius: 999rpx;
  border: 1rpx solid $morandi-border-strong;
  background: $morandi-bg-card-inner;
}

.ac-chip--on {
  border-color: #22c55e;
  background: rgba(34, 197, 94, 0.08);
}

.ac-chip__txt {
  font-size: 24rpx;
  color: $morandi-text-secondary;
  text-align: center;
  word-break: break-word;
  overflow-wrap: anywhere;
}

.ac-chip--on .ac-chip__txt {
  color: #15803d;
  font-weight: 600;
}

.ac-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;
}

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

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

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

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

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

/* 一行两列，列间距 20rpx（文档） */
.ac-pair {
  display: flex;
  flex-direction: row;
  align-items: stretch;
  gap: 20rpx;
  min-width: 0;
  box-sizing: border-box;
}

.ac-pair__col {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
}

.ac-card {
  flex: 1;
  min-height: 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 12rpx;
  padding: 12rpx;
  box-sizing: border-box;
  border-radius: 16rpx;
  background: $morandi-bg-card;
  border: 1rpx solid $morandi-border;
}

.ac-card__img {
  width: 100%;
  display: block;
}

.ac-card__title {
  font-size: 30rpx;
  font-weight: 600;
  line-height: 1.4;
  color: #111827;
  word-break: break-word;
  overflow-wrap: anywhere;
}

.ac-card__foot {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
  gap: 8rpx 12rpx;
  min-width: 0;
}

.ac-card__foot--video {
  justify-content: flex-start;
}

.ac-card__foot--train {
  justify-content: flex-start;
}

.ac-card__meta {
  font-size: 22rpx;
  line-height: 1.45;
  color: $morandi-accent-soft;
}

.ac-card__meta--muted {
  color: $morandi-text-soft;
}

.ac-card__meta--num {
  color: $morandi-text-secondary;
}

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

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

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