// AI_CHANGELOG
// - 2026-03-20 | Prompt: R3 项目类型筛选接口重建 | SKILL_OPTIONS value 从
//   all/chinese/snooker/mahjong/karaoke 改为 ALL/BILLIARD/SNOOKER/MAHJONG/KTV，
//   与后端枚举和数据库 category_code 一致。
// - 2026-03-23 | Prompt: 角色路由+页面权限守卫 | onShow 添加 checkPageAccess 权限守卫

import { checkPageAccess, getVisibleBoardTabs } from '../../utils/auth-guard'
// CHANGE 2026-03-28 | P4 联调：Mock → 真实 API
import { fetchBoardCoaches } from '../../services/api'
import { formatMoney, formatCount } from '../../utils/money'
import { formatHours } from '../../utils/time'
import { nameToAvatarColor } from '../../utils/avatar-color'

export {}

/** 排序维度 → 卡片模板映射 */
type DimType = 'perf' | 'salary' | 'sv' | 'task'

const SORT_TO_DIM: Record<string, DimType> = {
  perf_desc: 'perf',
  perf_asc: 'perf',
  salary_desc: 'salary',
  salary_asc: 'salary',
  sv_desc: 'sv',
  task_desc: 'task',
}

const SORT_OPTIONS = [
  { value: 'perf_desc', text: '定档业绩最高' },
  { value: 'perf_asc', text: '定档业绩最低' },
  { value: 'salary_desc', text: '工资最高' },
  { value: 'salary_asc', text: '工资最低' },
  { value: 'sv_desc', text: '客源储值最高' },
  { value: 'task_desc', text: '任务完成最多' },
]

// CHANGE 2026-03-20 | R3 修复：value 改为数据库 category_code，与后端枚举一致。
// 后续应改为调用 fetchSkillTypes() API 动态获取，此处作为 fallback。
const SKILL_OPTIONS = [
  { value: 'ALL', text: '不限' },
  { value: 'BILLIARD', text: '🎱 中式/追分' },
  { value: 'SNOOKER', text: '斯诺克' },
  { value: 'MAHJONG', text: '🀄 麻将/棋牌' },
  { value: 'KTV', text: '🎤 团建/K歌' },
]

const TIME_OPTIONS = [
  { value: 'month', text: '本月' },
  { value: 'quarter', text: '本季度' },
  { value: 'last_month', text: '上月' },
  { value: 'last_3m', text: '前3个月(不含本月)' },
  { value: 'last_quarter', text: '上季度' },
  { value: 'last_6m', text: '最近6个月(不含本月，不支持客源储值最高)' },
]

/** 等级 → 样式类映射 */
const LEVEL_CLASS: Record<string, string> = {
  star:   'level--star',
  senior: 'level--high',
  middle: 'level--mid',
  junior: 'level--low',
  // 兼容旧中文 key 过渡期
  '星级': 'level--star',
  '高级': 'level--high',
  '中级': 'level--mid',
  '初级': 'level--low',
}

/** 技能 → 样式类映射 */
const SKILL_CLASS: Record<string, string> = {
  '🎱': 'skill--chinese',
  '斯': 'skill--snooker',
  '🀄': 'skill--mahjong',
  '🎤': 'skill--karaoke',
}

interface CoachItem {
  id: string
  name: string
  initial: string
  avatarGradient: string
  level: string        // 英文 key: star | senior | middle | junior
  levelClass: string
  skills: Array<{ text: string; cls: string }>
  topCustomers: string[]
  // 定档业绩维度
  perfHours: number
  perfHoursBefore?: number
  perfGap?: string
  perfReached: boolean
  // 工资维度
  salary: number
  salaryPerfHours: number
  salaryPerfBefore?: number
  // 客源储值维度
  svAmount: number
  svCustomerCount: number
  svConsume: number
  // 任务维度
  taskRecall: number
  taskCallback: number
}

/** Mock 数据 — 2 个空字段骨架项，用于排查页面每个字段位置是否被覆盖 */
const MOCK_COACHES: CoachItem[] = [
  {
    id: '', name: '', initial: '',
    avatarGradient: '',
    level: 'junior', levelClass: LEVEL_CLASS['junior'],
    skills: [{ text: '', cls: '' }],
    topCustomers: ['', ''],
    perfHours: 0, perfHoursBefore: 0, perfGap: '', perfReached: false,
    salary: 0, salaryPerfHours: 0, salaryPerfBefore: 0,
    svAmount: 0, svCustomerCount: 0, svConsume: 0,
    taskRecall: 0, taskCallback: 0,
  },
  {
    id: '', name: '', initial: '',
    avatarGradient: '',
    level: 'middle', levelClass: LEVEL_CLASS['middle'],
    skills: [{ text: '', cls: '' }],
    topCustomers: ['', ''],
    perfHours: 0, perfGap: '', perfReached: false,
    salary: 0, salaryPerfHours: 0,
    svAmount: 0, svCustomerCount: 0, svConsume: 0,
    taskRecall: 0, taskCallback: 0,
  },
]

Page({
  data: {
    pageState: 'loading' as 'loading' | 'empty' | 'normal' | 'error',
    activeTab: 'coach' as 'finance' | 'customer' | 'coach',

    // CHANGE 2026-03-27 | 权限改造 W5：动态看板二级 tab
    boardTabs: [] as Array<{ key: string; label: string; active: boolean }>,

    selectedSort: 'perf_desc',
    sortOptions: SORT_OPTIONS,
    selectedSkill: 'ALL',
    skillOptions: SKILL_OPTIONS,
    selectedTime: 'month',
    timeOptions: TIME_OPTIONS,

    /** 当前维度类型，控制卡片模板 */
    dimType: 'perf' as DimType,

    coaches: [] as CoachItem[],
    allCoaches: [] as CoachItem[],

    /** 分页状态 */
    currentPage: 1,
    pageSize: 20,
    totalCount: 0,
    hasMore: true,
    isLoadingMore: false,

    /** 筛选栏可见性（滚动隐藏/显示） */
    filterBarVisible: true,
  },

  _lastScrollTop: 0,
  _scrollAcc: 0,
  _scrollDir: null as 'up' | 'down' | null,
  /** 请求代数计数器：切换筛选时递增，旧请求的响应到达后对比丢弃 */
  _loadGeneration: 0,

  onLoad() {
    this.loadData()
  },

  onShow() {
    // CHANGE 2026-03-27 | 权限改造 W5：checkPageAccess 完成后再刷新 boardTabs
    // checkPageAccess 内部会调用 /api/xcx/me 并同步 permissions 到 globalData
    checkPageAccess('pages/board-coach/board-coach').then((allowed) => {
      if (!allowed) return
      const TAB_LABELS: Record<string, string> = { finance: '财务', customer: '客户', coach: '助教' }
      const visibleKeys = getVisibleBoardTabs()
      this.setData({
        boardTabs: visibleKeys.map(k => ({ key: k, label: TAB_LABELS[k] || k, active: k === 'coach' })),
      })
    })
  },

  onPullDownRefresh() {
    this._loadGeneration++
    this.setData({ currentPage: 1, hasMore: true, coaches: [], allCoaches: [] })
    this.loadData()
    setTimeout(() => wx.stopPullDownRefresh(), 500)
  },

  /** 滚动隐藏/显示筛选栏 */
  onPageScroll(e: { scrollTop: number }) {
    const y = e.scrollTop
    const delta = y - this._lastScrollTop
    this._lastScrollTop = y

    if (y <= 8) {
      if (!this.data.filterBarVisible) this.setData({ filterBarVisible: true })
      this._scrollAcc = 0
      this._scrollDir = null
      return
    }

    if (Math.abs(delta) <= 2) return
    const dir = delta > 0 ? 'down' : 'up'
    if (dir !== this._scrollDir) {
      this._scrollDir = dir
      this._scrollAcc = 0
    }
    this._scrollAcc += Math.abs(delta)

    const threshold = dir === 'up' ? 12 : 24
    if (this._scrollAcc < threshold) return

    const visible = dir === 'up'
    if (this.data.filterBarVisible !== visible) {
      this.setData({ filterBarVisible: visible })
    }
    this._scrollAcc = 0
  },

  // CHANGE 2026-03-28 | P4 联调：替换 Mock 为真实 API 调用
  // CHANGE 2026-03-29 | 懒加载：支持分页追加
  // CHANGE 2026-04-08 | 竞态修复：用 _loadGeneration 丢弃过时响应
  async loadData() {
    const gen = this._loadGeneration
    const page = this.data.currentPage
    const isFirstPage = page === 1

    if (isFirstPage) {
      this.setData({ pageState: 'loading' })
      wx.showLoading({ title: '加载中...', mask: true })
    } else {
      if (this.data.isLoadingMore) return
      this.setData({ isLoadingMore: true })
    }

    try {
      const res = await fetchBoardCoaches({
        sort: this.data.selectedSort,
        skill: this.data.selectedSkill,
        time: this.data.selectedTime,
        page,
        pageSize: this.data.pageSize,
      })
      // 竞态保护：响应到达时代数已变（用户切了筛选），丢弃本次结果
      if (gen !== this._loadGeneration) return
      const items = res.items
      if (isFirstPage && (!items || items.length === 0)) {
        this.setData({ pageState: 'empty', totalCount: 0, hasMore: false })
        return
      }
      // 非首页返回空数据，标记到底
      if (!isFirstPage && (!items || items.length === 0)) {
        this.setData({ hasMore: false })
        return
      }
      // 后端返回 camelCase，映射为展示字段（传原始数字，WXML 用 WXS 格式化）
      const enriched = items.map((c: any) => ({
        ...c,
        levelClass: LEVEL_CLASS[c.level] || '',
        avatarGradient: nameToAvatarColor(String(c.id)),
        skills: c.skills || [],
        perfHoursLabel: formatHours(c.perfHours ?? 0),
        perfHoursBeforeLabel: c.perfHoursBefore ? formatHours(c.perfHoursBefore) : undefined,
        salaryLabel: formatMoney(c.salary ?? 0),
        salaryPerfHoursLabel: formatHours(c.salaryPerfHours ?? 0),
        salaryPerfBeforeLabel: c.salaryPerfBefore ? formatHours(c.salaryPerfBefore) : undefined,
        svAmountLabel: formatMoney(c.svAmount ?? 0),
        svCustomerCountLabel: formatCount(c.svCustomerCount ?? 0, '人'),
        svConsumeLabel: formatMoney(c.svConsume ?? 0),
        taskRecallLabel: `${c.taskRecall ?? 0}次`,
        taskCallbackLabel: `${c.taskCallback ?? 0}次`,
      }))

      // 追加时按 id 去重，避免 wx:key 重复警告
      let merged: any[]
      if (isFirstPage) {
        merged = enriched
      } else {
        const existIds = new Set(this.data.coaches.map((c: any) => c.id))
        const newItems = enriched.filter((c: any) => !existIds.has(c.id))
        merged = [...this.data.coaches, ...newItems]
      }
      // items 不足一页 或 已达 total，标记到底
      const hasMore = items.length >= this.data.pageSize && merged.length < res.total

      this.setData({
        allCoaches: merged,
        coaches: merged,
        totalCount: res.total,
        hasMore,
        pageState: 'normal',
      })
    } catch (e) {
      console.error('[board-coach] loadData 失败:', e)
      if (isFirstPage) this.setData({ pageState: 'error' })
    } finally {
      if (isFirstPage) wx.hideLoading()
      this.setData({ isLoadingMore: false })
    }
  },

  /** 触底加载下一页 */
  onReachBottom() {
    if (!this.data.hasMore || this.data.isLoadingMore) return
    this.setData({ currentPage: this.data.currentPage + 1 })
    this.loadData()
  },

  /** 看板 Tab 切换 — CHANGE 2026-03-29 | P1：redirectTo 替代 navigateTo，避免页面栈堆积 */
  onTabChange(e: WechatMiniprogram.TouchEvent) {
    const tab = e.currentTarget.dataset.tab as string
    if (tab === 'coach') return
    const routes: Record<string, { url: string; isTab: boolean }> = {
      finance: { url: '/pages/board-finance/board-finance', isTab: true },
      customer: { url: '/pages/board-customer/board-customer', isTab: false },
      coach: { url: '/pages/board-coach/board-coach', isTab: false },
    }
    const route = routes[tab]
    if (!route) return
    if (route.isTab) { wx.switchTab({ url: route.url }) } else { wx.redirectTo({ url: route.url }) }
  },

  onSortChange(e: WechatMiniprogram.CustomEvent<{ value: string }>) {
    const val = e.detail.value
    this._loadGeneration++
    this.setData({
      selectedSort: val,
      dimType: SORT_TO_DIM[val] || 'perf',
      currentPage: 1, hasMore: true, coaches: [], allCoaches: [],
    })
    this.loadData()
  },

  onSkillChange(e: WechatMiniprogram.CustomEvent<{ value: string }>) {
    this._loadGeneration++
    this.setData({ selectedSkill: e.detail.value, currentPage: 1, hasMore: true, coaches: [], allCoaches: [] })
    this.loadData()
  },

  onTimeChange(e: WechatMiniprogram.CustomEvent<{ value: string }>) {
    this._loadGeneration++
    this.setData({ selectedTime: e.detail.value, currentPage: 1, hasMore: true, coaches: [], allCoaches: [] })
    this.loadData()
  },

  onRetry() {
    this.loadData()
  },

  onCoachTap(e: WechatMiniprogram.TouchEvent) {
    const id = e.currentTarget.dataset.id as string
    wx.navigateTo({ url: '/pages/coach-detail/coach-detail?id=' + id })
  },
})
