<template>
  <div class="reward-config-form flex-1 min-h-0 flex flex-col">
    <ElCard shadow="never" class="form-card flex-1 min-h-0 flex flex-col">
      <template #header>
        <div class="card-header">
          <span>{{ $t('page.toolbar.gameRewardConfig') }}</span>
          <ElButton
            v-permission="'dice:reward_config:index:createRewardReference'"
            type="warning"
            :loading="createRewardLoading"
            @click="handleCreateRewardReference"
            v-ripple
            :title="$t('page.toolbar.createRewardRefTitle')"
          >
            {{ $t('page.toolbar.createRewardRef') }}
          </ElButton>
        </div>
      </template>

      <ElTabs v-model="activeTab" type="card" class="top-tabs">
        <ElTabPane :label="$t('page.configPage.tabIndex')" name="index">
          <div class="tab-panel">
            <div class="panel-tip">{{ $t('page.configPage.tipIndex') }}</div>
            <div v-if="canTierRecommend" class="tier-recommend-panel">
              <div class="tier-recommend-rules">{{ $t('page.configPage.tierRecommendRules') }}</div>
              <div class="tier-recommend-grid">
                <div v-for="tk in TIER_RECOMMEND_KEYS" :key="tk" class="tier-recommend-cell">
                  <span class="tier-recommend-label">{{ tk }}</span>
                  <span class="tier-recommend-hint">{{ $t('page.configPage.tierRecommendRealEv') }}</span>
                  <ElInputNumber
                    v-model="tierRecommend[tk]"
                    :disabled="tk === 'T5'"
                    :step="0.1"
                    :precision="2"
                    controls-position="right"
                    size="small"
                    class="tier-recommend-input"
                  />
                </div>
              </div>
              <div class="tier-recommend-actions">
                <ElCheckbox v-model="autoMatchTierOnRealEv">{{
                  $t('page.configPage.tierRecommendAutoMatch')
                }}</ElCheckbox>
                <ElButton size="small" @click="handleApplyRecommendRealEv" v-ripple>{{
                  $t('page.configPage.tierRecommendApplyAmount')
                }}</ElButton>
                <ElButton size="small" type="primary" plain @click="handleMatchAllTiersFromRealEv" v-ripple>{{
                  $t('page.configPage.tierRecommendMatchTier')
                }}</ElButton>
              </div>
            </div>
            <div v-if="canTierRecommend" class="index-toolbar">
              <ElButton
                v-permission="PERM_TIER_RECOMMEND"
                type="default"
                @click="openRuleGenerateDialog"
                v-ripple
              >
                {{ $t('page.configPage.btnRuleGenerate') }}
              </ElButton>
            </div>
            <div class="table-scroll-wrap">
              <ElTable
                v-loading="loading"
                :data="indexRowsExcludeBigwin"
                border
                size="default"
                class="config-table"
              >
                <ElTableColumn
                  :label="$t('page.configPage.colId')"
                  prop="id"
                  width="60"
                  align="center"
                >
                  <template #default="{ row }">
                    <span>{{ row.id }}</span>
                  </template>
                </ElTableColumn>
                <ElTableColumn
                  :label="$t('page.configPage.colDicePoints')"
                  min-width="100"
                  align="center"
                >
                  <template #default="{ row }">
                    <ElInputNumber
                      v-model="row.grid_number"
                      :min="5"
                      :max="30"
                      controls-position="right"
                      size="small"
                      class="full-width"
                    />
                  </template>
                </ElTableColumn>
                <ElTableColumn
                  :label="$t('page.configPage.colDisplayText')"
                  min-width="100"
                  align="center"
                >
                  <template #default="{ row }">
                    <ElInput
                      v-model="row.ui_text"
                      size="small"
                      :placeholder="$t('page.configPage.placeholderDisplayZh')"
                    />
                  </template>
                </ElTableColumn>
                <ElTableColumn
                  :label="$t('page.configPage.colDisplayTextEn')"
                  min-width="120"
                  align="center"
                >
                  <template #default="{ row }">
                    <ElInput
                      v-model="row.ui_text_en"
                      size="small"
                      :placeholder="$t('page.configPage.placeholderDisplayEn')"
                    />
                  </template>
                </ElTableColumn>
                <ElTableColumn
                  :label="$t('page.configPage.colRealEv')"
                  min-width="110"
                  align="center"
                >
                  <template #default="{ row }">
                    <ElInputNumber
                      v-model="row.real_ev"
                      controls-position="right"
                      size="small"
                      :step="0.1"
                      :precision="2"
                      class="full-width"
                      @update:model-value="() => handleRealEvChange(row)"
                    />
                  </template>
                </ElTableColumn>
                <ElTableColumn :label="$t('page.configPage.colTier')" width="100" align="center">
                  <template #default="{ row }">
                    <span class="tier-readonly">{{ displayRowTier(row) }}</span>
                  </template>
                </ElTableColumn>
                <ElTableColumn
                  :label="$t('page.configPage.colRemark')"
                  min-width="140"
                  align="center"
                >
                  <template #default="{ row }">
                    <ElInput
                      v-model="row.remark"
                      size="small"
                      :placeholder="remarkPlaceholderForRow(row)"
                    />
                  </template>
                </ElTableColumn>
              </ElTable>
            </div>
            <div class="tab-footer">
              <ElButton
                v-permission="'dice:reward_config:index:batchUpdate'"
                type="primary"
                :loading="savingIndex"
                @click="handleSaveIndex"
                >{{ $t('page.configPage.btnSave') }}</ElButton
              >
              <ElButton @click="handleResetIndex">{{ $t('page.configPage.btnReset') }}</ElButton>
            </div>
          </div>
        </ElTabPane>
        <ElTabPane :label="$t('page.configPage.tabBigwin')" name="bigwin">
          <div class="tab-panel">
            <div class="panel-tip">{{ $t('page.configPage.tipBigwin') }}</div>
            <div class="table-scroll-wrap">
              <ElTable
                v-loading="loading"
                :data="bigwinRows"
                row-key="id"
                border
                size="default"
                class="config-table bigwin-table"
              >
                <ElTableColumn
                  :label="$t('page.configPage.colBigwinPoints')"
                  width="100"
                  align="center"
                >
                  <template #default="{ row }">
                    <span class="readonly-value">{{ row.grid_number }}</span>
                  </template>
                </ElTableColumn>
                <ElTableColumn
                  :label="$t('page.configPage.colDisplayInfo')"
                  min-width="140"
                  align="center"
                >
                  <template #default="{ row }">
                    <ElInput
                      v-model="row.ui_text"
                      size="small"
                      :placeholder="$t('page.configPage.placeholderDisplayInfoZh')"
                    />
                  </template>
                </ElTableColumn>
                <ElTableColumn
                  :label="$t('page.configPage.colDisplayInfoEn')"
                  min-width="160"
                  align="center"
                >
                  <template #default="{ row }">
                    <ElInput
                      v-model="row.ui_text_en"
                      size="small"
                      :placeholder="$t('page.configPage.placeholderDisplayInfoEn')"
                    />
                  </template>
                </ElTableColumn>
                <ElTableColumn
                  :label="$t('page.configPage.colRealPrize')"
                  min-width="120"
                  align="center"
                >
                  <template #default="{ row }">
                    <ElInputNumber
                      v-model="row.real_ev"
                      controls-position="right"
                      size="small"
                      :step="0.1"
                      :precision="2"
                      class="full-width"
                      @update:model-value="() => handleRealEvChange(row)"
                    />
                  </template>
                </ElTableColumn>
                <ElTableColumn
                  :label="$t('page.configPage.colRemark')"
                  min-width="140"
                  align="center"
                >
                  <template #default="{ row }">
                    <ElInput
                      v-model="row.remark"
                      size="small"
                      :placeholder="remarkPlaceholderForRow(row)"
                    />
                  </template>
                </ElTableColumn>
                <ElTableColumn
                  :label="$t('page.configPage.colWeightRange')"
                  min-width="220"
                  align="center"
                >
                  <template #default="{ row }">
                    <div class="weight-cell">
                      <ElSlider
                        :model-value="row.weight"
                        :min="0"
                        :max="10000"
                        :step="100"
                        :disabled="isBigwinWeightDisabled(row)"
                        @update:model-value="
                          (v: number | number[]) => setBigwinRowWeight(row, Array.isArray(v) ? v[0] : v)
                        "
                      />
                      <ElInputNumber
                        :model-value="row.weight"
                        :min="0"
                        :max="10000"
                        :step="100"
                        :disabled="isBigwinWeightDisabled(row)"
                        controls-position="right"
                        size="small"
                        class="weight-input"
                        @update:model-value="(v: number | undefined) => setBigwinRowWeight(row, v)"
                      />
                    </div>
                    <span v-if="isBigwinWeightDisabled(row)" class="weight-tip">{{
                      $t('page.configPage.weightFixedTip')
                    }}</span>
                  </template>
                </ElTableColumn>
              </ElTable>
            </div>
            <div v-if="bigwinRows.length === 0 && !loading" class="empty-tip">
              {{ $t('page.configPage.emptyBigwin') }}
            </div>
            <div class="tab-footer">
              <ElButton
                v-permission="'dice:reward_config:index:saveBigwinWeightsByGrid'"
                type="primary"
                :loading="savingBigwin"
                @click="handleSaveBigwin"
                >{{ $t('page.configPage.btnSave') }}</ElButton
              >
              <ElButton @click="handleResetBigwin">{{ $t('page.configPage.btnReset') }}</ElButton>
            </div>
          </div>
        </ElTabPane>
      </ElTabs>
    </ElCard>

    <ElDialog
      v-if="canTierRecommend"
      v-model="ruleGenerateDialogVisible"
      :title="$t('page.configPage.ruleGenerateTitle')"
      :width="ruleGenDialogWidth"
      :fullscreen="ruleGenFullscreen"
      align-center
      destroy-on-close
      :close-on-click-modal="false"
      class="rule-generate-dialog"
    >
      <div class="rule-generate-rules">{{ $t('page.configPage.ruleGenerateRules') }}</div>
      <ElForm
        :label-position="ruleGenFormLabelPosition"
        :label-width="ruleGenFormLabelWidth"
        class="rule-generate-form"
        @submit.prevent
      >
        <ElFormItem :label="$t('page.configPage.ruleGenT1Row')">
          <div class="rule-gen-row">
            <div class="rule-gen-cell">
              <span class="rule-gen-hint">{{ $t('page.configPage.ruleGenFixedCount') }}</span>
              <ElInputNumber
                v-model="ruleGenT1Fixed"
                class="rule-gen-input-num"
                :min="0"
                :max="26"
                :step="1"
                :controls="ruleGenInputControls"
                :size="ruleGenInputSize"
                controls-position="right"
              />
            </div>
            <div class="rule-gen-cell">
              <span class="rule-gen-hint">{{ $t('page.configPage.ruleGenRealEvStd') }}</span>
              <ElInputNumber
                v-model="ruleGenT1RealEv"
                class="rule-gen-input-num"
                :step="1"
                :controls="ruleGenInputControls"
                :size="ruleGenInputSize"
                controls-position="right"
              />
            </div>
          </div>
        </ElFormItem>
        <ElFormItem :label="$t('page.configPage.ruleGenT2Row')">
          <div class="rule-gen-row">
            <div class="rule-gen-cell">
              <span class="rule-gen-hint">{{ $t('page.configPage.ruleGenMinCount') }}</span>
              <ElInputNumber
                v-model="ruleGenT2Min"
                class="rule-gen-input-num"
                :min="0"
                :max="26"
                :step="1"
                :controls="ruleGenInputControls"
                :size="ruleGenInputSize"
                controls-position="right"
              />
            </div>
            <div class="rule-gen-cell">
              <span class="rule-gen-hint">{{ $t('page.configPage.ruleGenRealEvStd') }}</span>
              <ElInputNumber
                v-model="ruleGenT2RealEv"
                class="rule-gen-input-num"
                :step="1"
                :controls="ruleGenInputControls"
                :size="ruleGenInputSize"
                controls-position="right"
              />
            </div>
          </div>
        </ElFormItem>
        <ElFormItem :label="$t('page.configPage.ruleGenT3RealEvOnly')">
          <div class="rule-gen-row">
            <div class="rule-gen-cell">
              <span class="rule-gen-hint">{{ $t('page.configPage.ruleGenRealEvStd') }}</span>
              <ElInputNumber
                v-model="ruleGenT3RealEv"
                class="rule-gen-input-num"
                :step="1"
                :controls="ruleGenInputControls"
                :size="ruleGenInputSize"
                controls-position="right"
              />
            </div>
          </div>
        </ElFormItem>
        <ElFormItem :label="$t('page.configPage.ruleGenT4Row')">
          <div class="rule-gen-row">
            <div class="rule-gen-cell">
              <span class="rule-gen-hint">{{ $t('page.configPage.ruleGenFixedCount') }}</span>
              <ElInputNumber
                v-model="ruleGenT4Fixed"
                class="rule-gen-input-num"
                :min="0"
                :max="26"
                :step="1"
                :controls="ruleGenInputControls"
                :size="ruleGenInputSize"
                controls-position="right"
              />
            </div>
            <div class="rule-gen-cell">
              <span class="rule-gen-hint">{{ $t('page.configPage.ruleGenRealEvStd') }}</span>
              <ElInputNumber
                v-model="ruleGenT4RealEv"
                class="rule-gen-input-num"
                :disabled="true"
                :step="1"
                :controls="ruleGenInputControls"
                :size="ruleGenInputSize"
                controls-position="right"
              />
            </div>
          </div>
        </ElFormItem>
        <ElFormItem :label="$t('page.configPage.ruleGenT5Row')">
          <div class="rule-gen-row">
            <div class="rule-gen-cell">
              <span class="rule-gen-hint">{{ $t('page.configPage.ruleGenFixedCount') }}</span>
              <ElInputNumber
                v-model="ruleGenT5Fixed"
                class="rule-gen-input-num"
                :min="0"
                :max="26"
                :step="1"
                :controls="ruleGenInputControls"
                :size="ruleGenInputSize"
                controls-position="right"
              />
            </div>
            <div class="rule-gen-cell">
              <span class="rule-gen-hint">{{ $t('page.configPage.ruleGenRealEvStd') }}</span>
              <ElInputNumber
                v-model="ruleGenT5RealEv"
                class="rule-gen-input-num"
                :step="0.1"
                :precision="2"
                :controls="ruleGenInputControls"
                :size="ruleGenInputSize"
                controls-position="right"
              />
            </div>
          </div>
        </ElFormItem>
        <p class="rule-generate-scope">{{ $t('page.configPage.ruleGenScopeHint') }}</p>
        <p class="rule-generate-scope">{{ $t('page.configPage.ruleGenRealEvEditHint') }}</p>
      </ElForm>
      <template #footer>
        <div class="rule-gen-footer-btns">
          <ElButton @click="ruleGenerateDialogVisible = false">{{ $t('common.cancel') }}</ElButton>
          <ElButton type="primary" :loading="ruleGenSubmitting" @click="handleRuleGenerateApply">
            {{ $t('page.configPage.ruleGenApply') }}
          </ElButton>
        </div>
      </template>
    </ElDialog>

    <CreateRewardReferencePreviewDialog
      v-model="createRewardPreviewVisible"
      :dept-id="filterDeptId"
      @success="loadIndexList"
    />
  </div>
</template>

<script setup lang="ts">
  import {
    DEFAULT_CHANNEL_ID,
    getChannelDeptRequestParams,
    useChannelDeptReload,
    useInjectedChannelDept
  } from '@/composables/useChannelDeptScope'
  import { useWindowSize } from '@vueuse/core'
  import { ElMessage } from 'element-plus'
  import { useI18n } from 'vue-i18n'
  import api from '../../api/reward_config/index'
  import { checkAuth } from '@/utils/tool'
  import CreateRewardReferencePreviewDialog from './modules/create-reward-reference-preview-dialog.vue'
  import {
    buildRowsFromTiers,
    computeBoardFrequencies,
    DEFAULT_TIER_REAL_EV_STANDARDS,
    defaultRemarkForTier,
    generateTiers,
    inferTierFromRealEv,
    summarizeCounts,
    type TierRealEvStandards,
    validateTierRealEvStandards
  } from '../utils/generateIndexByRules'

  const { t } = useI18n()

  /** 档位结算推荐配置（T1-T5 推荐金额栏、按规则生成/导入） */
  const PERM_TIER_RECOMMEND = 'dice:reward_config:index:tierRecommend'
  const canTierRecommend = computed(() => checkAuth(PERM_TIER_RECOMMEND))

  const { width: viewportWidth } = useWindowSize()
  /** 窄屏：单列、标签置顶、全屏弹窗 */
  const isRuleGenMobile = computed(() => viewportWidth.value < 640)
  const ruleGenDialogWidth = computed(() => (isRuleGenMobile.value ? '100%' : 'min(880px, 92vw)'))
  const ruleGenFullscreen = computed(() => isRuleGenMobile.value)
  const ruleGenFormLabelPosition = computed(() => (isRuleGenMobile.value ? 'top' : 'right'))
  const ruleGenFormLabelWidth = computed(() => (isRuleGenMobile.value ? undefined : '168px'))
  /** 移动端隐藏步进按钮，避免误触；用系统数字键盘输入 */
  const ruleGenInputControls = computed(() => !isRuleGenMobile.value)
  const ruleGenInputSize = computed(() => (isRuleGenMobile.value ? 'large' : 'default'))

  /** 第一页：奖励索引行（来自 DiceRewardConfig 表） */
  interface IndexRow {
    id: number
    grid_number: number
    ui_text: string
    ui_text_en: string
    real_ev: number
    tier: string
    remark: string
    weight: number
  }

  const channelScope = useInjectedChannelDept()
  const filterDeptId = computed(() => {
    const scopedId = channelScope?.selectedDeptId.value
    if (scopedId !== undefined && scopedId !== null) {
      if (scopedId > 0 || channelScope?.showDefaultTemplate.value) {
        return scopedId
      }
    }
    const extra = getChannelDeptRequestParams()
    if (extra.dept_id !== undefined) {
      return extra.dept_id
    }
    return DEFAULT_CHANNEL_ID
  })

  const activeTab = ref<'index' | 'bigwin'>('index')
  const loading = ref(false)
  const savingIndex = ref(false)
  const savingBigwin = ref(false)
  const createRewardLoading = ref(false)
  const createRewardPreviewVisible = ref(false)
  const ruleGenerateDialogVisible = ref(false)
  const ruleGenSubmitting = ref(false)
  const ruleGenT1Fixed = ref(3)
  const ruleGenT2Min = ref(5)
  const ruleGenT4Fixed = ref(1)
  const ruleGenT5Fixed = ref(1)
  const TIER_RECOMMEND_KEYS = ['T1', 'T2', 'T3', 'T4', 'T5'] as const
  type TierRecommendKey = (typeof TIER_RECOMMEND_KEYS)[number]

  const tierRecommend = reactive<TierRealEvStandards>({
    T1: DEFAULT_TIER_REAL_EV_STANDARDS.T1,
    T2: DEFAULT_TIER_REAL_EV_STANDARDS.T2,
    T3: DEFAULT_TIER_REAL_EV_STANDARDS.T3,
    T4: DEFAULT_TIER_REAL_EV_STANDARDS.T4,
    T5: DEFAULT_TIER_REAL_EV_STANDARDS.T5
  })
  const autoMatchTierOnRealEv = ref(false)

  const ruleGenT1RealEv = ref(DEFAULT_TIER_REAL_EV_STANDARDS.T1)
  const ruleGenT2RealEv = ref(DEFAULT_TIER_REAL_EV_STANDARDS.T2)
  const ruleGenT3RealEv = ref(DEFAULT_TIER_REAL_EV_STANDARDS.T3)
  const ruleGenT4RealEv = ref(DEFAULT_TIER_REAL_EV_STANDARDS.T4)
  const ruleGenT5RealEv = ref(DEFAULT_TIER_REAL_EV_STANDARDS.T5)

  function syncRuleGenFromTierRecommend() {
    ruleGenT1RealEv.value = tierRecommend.T1
    ruleGenT2RealEv.value = tierRecommend.T2
    ruleGenT3RealEv.value = tierRecommend.T3
    ruleGenT4RealEv.value = tierRecommend.T4
    ruleGenT5RealEv.value = tierRecommend.T5
  }

  function syncTierRecommendFromRuleGen() {
    tierRecommend.T1 = Number(ruleGenT1RealEv.value)
    tierRecommend.T2 = Number(ruleGenT2RealEv.value)
    tierRecommend.T3 = Number(ruleGenT3RealEv.value)
    tierRecommend.T4 = Number(ruleGenT4RealEv.value)
    tierRecommend.T5 = Number(ruleGenT5RealEv.value)
  }

  function applyRealEvDisplay(row: IndexRow, n: number) {
    const text = Number.isNaN(n) ? '' : Number(n).toFixed(2)
    row.ui_text = text
    row.ui_text_en = text
  }

  function rowRealEvNumber(row: IndexRow): number {
    return typeof row.real_ev === 'number' && !Number.isNaN(row.real_ev)
      ? row.real_ev
      : Number(row.real_ev)
  }

  function syncRowTierFromRealEv(row: IndexRow) {
    const tier = inferTierFromRealEv(rowRealEvNumber(row))
    if (tier !== '') {
      row.tier = tier
    }
  }

  /** 按当前结算金额推断档位并写入对应备注（T1大奖/T2小赚/T3抽水/T4惩罚/T5再来一次） */
  function syncRemarkFromSettlement(row: IndexRow) {
    const tier = inferTierFromRealEv(rowRealEvNumber(row))
    if (tier === '') {
      return
    }
    row.remark = defaultRemarkForTier(tier)
  }

  function remarkPlaceholderForRow(row: IndexRow): string {
    const tier = displayRowTier(row)
    if (tier === '' || tier === '-') {
      return t('page.configPage.placeholderRemark')
    }
    return defaultRemarkForTier(tier)
  }

  function displayRowTier(row: IndexRow): string {
    const tier = inferTierFromRealEv(rowRealEvNumber(row))
    return tier !== '' ? tier : row.tier || '-'
  }

  function applyRecommendRealEvToRow(row: IndexRow, tier: TierRecommendKey) {
    const ev = tierRecommend[tier]
    row.real_ev = ev
    if (tier === 'T5') {
      row.ui_text = t('page.configPage.tierRecommendT5UiText')
      row.ui_text_en = t('page.configPage.tierRecommendT5UiTextEn')
    } else {
      applyRealEvDisplay(row, ev)
    }
    syncRowTierFromRealEv(row)
    syncRemarkFromSettlement(row)
  }

  /** 奖励索引 id 与后端 DiceRewardConfigLogic 一致：0～25 */
  const REWARD_INDEX_MIN = 0
  const REWARD_INDEX_MAX = 25
  const ALLOWED_INDEX_TIERS = ['T1', 'T2', 'T3', 'T4', 'T5', 'BIGWIN'] as const

  /** 第一页数据（来自 api.list，即 DiceRewardConfig 表） */
  const indexRows = ref<IndexRow[]>([])
  /** 奖励索引 Tab：排除 tier=BIGWIN，仅显示 T1～T5 */
  const indexRowsExcludeBigwin = computed(() => indexRows.value.filter((r) => r.tier !== 'BIGWIN'))
  /** 第二页 BIGWIN 数据：来自同一张表 DiceRewardConfig，过滤 tier===BIGWIN */
  const bigwinRows = computed(() => indexRows.value.filter((r) => r.tier === 'BIGWIN'))
  /** 原始 list 快照，用于重置 */
  let indexRowsSnapshot: IndexRow[] = []

  function isAllowedIndexTier(s: string): boolean {
    for (let i = 0; i < ALLOWED_INDEX_TIERS.length; i++) {
      if (ALLOWED_INDEX_TIERS[i] === s) {
        return true
      }
    }
    return false
  }

  function toWeight(v: unknown): number {
    const n = typeof v === 'number' && !Number.isNaN(v) ? v : Number(v)
    if (Number.isNaN(n)) return 0
    return Math.max(0, Math.min(10000, Math.floor(n)))
  }

  function normalizeIndexRow(raw: Record<string, unknown>): IndexRow {
    return {
      id: Number(raw.id) ?? 0,
      grid_number: Number(raw.grid_number) ?? 0,
      ui_text: String(raw.ui_text ?? ''),
      ui_text_en: String((raw as any).ui_text_en ?? ''),
      real_ev: Number(raw.real_ev) ?? 0,
      tier: String(raw.tier ?? ''),
      remark: String(raw.remark ?? ''),
      weight: toWeight((raw as any).weight)
    }
  }

  /** BIGWIN 行不参与按 real_ev 推断 T1-T5，避免编辑时从大奖权重表消失 */
  function setBigwinRowWeight(row: IndexRow, v: number | number[] | undefined | null) {
    const n = Array.isArray(v) ? v[0] : v
    row.weight = toWeight(n)
  }

  function handleRealEvChange(row: IndexRow) {
    if (row.tier === 'BIGWIN') {
      row.remark = defaultRemarkForTier('BIGWIN')
      return
    }
    const n = rowRealEvNumber(row)
    syncRowTierFromRealEv(row)
    const tier = inferTierFromRealEv(n)
    if (tier === 'T5') {
      row.ui_text = t('page.configPage.tierRecommendT5UiText')
      row.ui_text_en = t('page.configPage.tierRecommendT5UiTextEn')
    } else {
      applyRealEvDisplay(row, n)
    }
    syncRemarkFromSettlement(row)
  }

  function handleApplyRecommendRealEv() {
    if (!canTierRecommend.value) {
      return
    }
    let count = 0
    for (const row of indexRowsExcludeBigwin.value) {
      const tier = inferTierFromRealEv(rowRealEvNumber(row))
      if (tier === 'T1' || tier === 'T2' || tier === 'T3' || tier === 'T4' || tier === 'T5') {
        applyRecommendRealEvToRow(row, tier)
        count++
      }
    }
    if (count === 0) {
      ElMessage.info(t('page.configPage.tierRecommendNoTierRows'))
      return
    }
    ElMessage.success(t('page.configPage.tierRecommendApplyAmountOk', { n: count }))
  }

  function handleMatchAllTiersFromRealEv() {
    if (!canTierRecommend.value) {
      return
    }
    let count = 0
    for (const row of indexRowsExcludeBigwin.value) {
      syncRowTierFromRealEv(row)
      syncRemarkFromSettlement(row)
      if (row.tier !== '') {
        count++
      }
    }
    if (count === 0) {
      ElMessage.info(t('page.configPage.tierRecommendMatchTierNone'))
      return
    }
    ElMessage.success(t('page.configPage.tierRecommendMatchTierOk', { n: count }))
  }

  function formatMoney2(val: unknown): string {
    if (val === '' || val === null || val === undefined) return '-'
    const n = typeof val === 'number' ? val : Number(val)
    if (!Number.isFinite(n)) return '-'
    return n.toFixed(2)
  }

  async function handleCreateRewardReference() {
    createRewardPreviewVisible.value = true
  }

  function extractIndexList(res: unknown): Record<string, unknown>[] {
    if (Array.isArray(res)) {
      return res as Record<string, unknown>[]
    }
    if (res && typeof res === 'object') {
      const obj = res as Record<string, unknown>
      if (Array.isArray(obj.data)) {
        return obj.data as Record<string, unknown>[]
      }
      if (Array.isArray(obj.records)) {
        return obj.records as Record<string, unknown>[]
      }
    }
    return []
  }

  function loadIndexList() {
    loading.value = true
    return api
      .list({ saiType: 'all', limit: 200, dept_id: filterDeptId.value })
      .then((res: unknown) => {
        const rows = extractIndexList(res).map((r) => normalizeIndexRow(r))
        for (const row of rows) {
          if (row.tier !== 'BIGWIN') {
            syncRowTierFromRealEv(row)
          }
        }
        indexRows.value = rows
        indexRowsSnapshot = rows.map((r) => ({ ...r }))
      })
      .catch(() => {
        ElMessage.error(t('page.configPage.loadIndexFail'))
      })
      .finally(() => {
        loading.value = false
      })
  }

  /** 挂载时拉数；超管切换左侧渠道时重新拉数 */
  useChannelDeptReload(loadIndexList)
  watch(
    () => filterDeptId.value,
    (deptId, prev) => {
      if (deptId !== prev) {
        loadIndexList()
      }
    }
  )

  function isBigwinWeightDisabled(row: IndexRow): boolean {
    return row.grid_number === 5 || row.grid_number === 30
  }

  const GRID_NUMBER_MIN = 5
  const GRID_NUMBER_MAX = 30

  /** 找出数组中出现多于一次的值 */
  function findDuplicateValues(arr: number[]): number[] {
    const count = new Map<number, number>()
    for (const v of arr) {
      count.set(v, (count.get(v) ?? 0) + 1)
    }
    const duplicates: number[] = []
    count.forEach((c, v) => {
      if (c > 1) duplicates.push(v)
    })
    return duplicates.sort((a, b) => a - b)
  }

  /** 奖励索引表单校验：仅对本表内的行（不含 BIGWIN）校验，点数 5～30 且本批内不重复 */
  function validateIndexFormForSaveRows(rows: IndexRow[]): string | null {
    const toSave = rows.filter((r) => r.tier !== 'BIGWIN')
    if (toSave.length === 0) {
      return t('page.configPage.warnNoIndexToSave')
    }
    const nums = toSave.map((r) => Number(r.grid_number))
    const outOfRange = nums.filter(
      (n) => Number.isNaN(n) || n < GRID_NUMBER_MIN || n > GRID_NUMBER_MAX
    )
    if (outOfRange.length > 0) {
      return t('page.configPage.warnGridRange', { min: GRID_NUMBER_MIN, max: GRID_NUMBER_MAX })
    }
    const duplicates = findDuplicateValues(nums)
    if (duplicates.length > 0) {
      return t('page.configPage.warnDupGrid', {
        list: duplicates.join(t('page.configPage.dupJoiner'))
      })
    }
    return null
  }

  function validateIndexFormForSave(): string | null {
    return validateIndexFormForSaveRows(indexRows.value)
  }

  /** 从当前表提取 id 0～25 的色子点数（不含 BIGWIN），用于按规则生成 */
  function extractGrids26(): number[] | null {
    const map = new Map<number, number>()
    for (const r of indexRows.value) {
      if (r.tier === 'BIGWIN') {
        continue
      }
      if (r.id >= REWARD_INDEX_MIN && r.id <= REWARD_INDEX_MAX) {
        map.set(r.id, Number(r.grid_number))
      }
    }
    const out: number[] = []
    for (let id = REWARD_INDEX_MIN; id <= REWARD_INDEX_MAX; id++) {
      if (!map.has(id)) {
        return null
      }
      const gn = map.get(id)
      if (gn === undefined || Number.isNaN(gn)) {
        return null
      }
      out.push(gn)
    }
    return out
  }

  function openRuleGenerateDialog() {
    if (!canTierRecommend.value) {
      return
    }
    syncRuleGenFromTierRecommend()
    ruleGenerateDialogVisible.value = true
  }

  function applyGeneratedRowsToIndex(
    items: Array<{
      id: number
      grid_number: number
      ui_text: string
      ui_text_en: string
      real_ev: number
      tier: string
      remark: string
    }>
  ): string | null {
    const next = indexRows.value.map((r) => ({ ...r }))
    for (const item of items) {
      const row = next.find((x) => x.id === item.id)
      if (row === undefined) {
        return t('page.configPage.ruleGenUnknownId', { id: item.id })
      }
      row.grid_number = item.grid_number
      row.ui_text = item.ui_text
      row.ui_text_en = item.ui_text_en
      row.real_ev = item.real_ev
      row.tier = item.tier
      row.remark = item.remark
    }
    const err = validateIndexFormForSaveRows(next)
    if (err) {
      return err
    }
    indexRows.value = next
    return null
  }

  async function handleRuleGenerateApply() {
    if (!canTierRecommend.value) {
      return
    }
    const grids = extractGrids26()
    if (grids === null) {
      ElMessage.warning(t('page.configPage.ruleGenNeedFullGrid'))
      return
    }
    const t1 = Math.max(0, Math.min(26, Math.floor(Number(ruleGenT1Fixed.value))))
    const t2 = Math.max(0, Math.min(26, Math.floor(Number(ruleGenT2Min.value))))
    const x4 = Math.max(0, Math.min(26, Math.floor(Number(ruleGenT4Fixed.value))))
    const x5 = Math.max(0, Math.min(26, Math.floor(Number(ruleGenT5Fixed.value))))
    syncTierRecommendFromRuleGen()
    const standards = {
      T1: Number(tierRecommend.T1),
      T2: Number(tierRecommend.T2),
      T3: Number(tierRecommend.T3),
      T4: Number(tierRecommend.T4),
      T5: Number(tierRecommend.T5)
    }
    const invalidKey = validateTierRealEvStandards(standards)
    if (invalidKey !== null) {
      ElMessage.warning(t(`page.configPage.${invalidKey}`))
      return
    }
    const constraints = {
      t1FixedCw: t1,
      t2MinCw: t2,
      t4FixedCw: x4,
      t5FixedCw: x5,
      t1FixedCcw: t1,
      t2MinCcw: t2,
      t4FixedCcw: x4,
      t5FixedCcw: x5
    }
    const gen = generateTiers({ grids, constraints })
    if (!gen.ok) {
      ElMessage.warning(gen.message)
      return
    }
    const built = buildRowsFromTiers(grids, gen.tiers, standards)
    const mergeErr = applyGeneratedRowsToIndex(built)
    if (mergeErr) {
      ElMessage.warning(mergeErr)
      return
    }
    const board = computeBoardFrequencies(grids)
    if (board === null) {
      ElMessage.warning(t('page.configPage.ruleGenFreqFail'))
      return
    }
    const sc = summarizeCounts(board, gen.tiers)
    ruleGenSubmitting.value = true
    try {
      const indexPayload = built.map(
        (r: {
          id: number
          grid_number: number
          ui_text: string
          ui_text_en: string
          real_ev: number
          tier: string
          remark: string
        }) => ({
          id: r.id,
          grid_number: r.grid_number,
          ui_text: r.ui_text,
          ui_text_en: r.ui_text_en,
          real_ev: r.real_ev,
          tier: r.tier,
          remark: r.remark
        })
      )
      await api.generateIndexByRules(indexPayload, { dept_id: filterDeptId.value })
      ElMessage.success(
        t('page.configPage.ruleGenSuccess', {
          cwT1: sc.cw.T1,
          cwT2: sc.cw.T2,
          cwT4: sc.cw.T4,
          cwT5: sc.cw.T5,
          ccT1: sc.ccw.T1,
          ccT2: sc.ccw.T2,
          ccT4: sc.ccw.T4,
          ccT5: sc.ccw.T5
        })
      )
      indexRowsSnapshot = indexRows.value.map((r) => ({ ...r }))
      ruleGenerateDialogVisible.value = false
    } catch (e: unknown) {
      let msg = ''
      if (e !== null && typeof e === 'object' && 'message' in e) {
        const m = Reflect.get(e, 'message')
        if (typeof m === 'string') {
          msg = m
        }
      }
      ElMessage.error(msg || t('page.configPage.saveFail'))
      loadIndexList()
    } finally {
      ruleGenSubmitting.value = false
    }
  }

  /** 奖励索引表单：仅提交本表数据（T1～T5），不包含大奖权重 */
  async function handleSaveIndex() {
    const err = validateIndexFormForSave()
    if (err) {
      ElMessage.warning(err)
      return
    }
    const toSave = indexRows.value.filter((r) => r.tier !== 'BIGWIN')
    for (const row of toSave) {
      syncRowTierFromRealEv(row)
    }
    savingIndex.value = true
    try {
      const indexPayload = toSave.map((r) => ({
        id: r.id,
        grid_number: r.grid_number,
        ui_text: r.ui_text,
        ui_text_en: r.ui_text_en,
        real_ev: r.real_ev,
        tier: r.tier,
        remark: r.remark
      }))
      await api.batchUpdate(indexPayload, { dept_id: filterDeptId.value })
      ElMessage.success(t('page.configPage.saveSuccess'))
      indexRowsSnapshot = indexRows.value.map((r) => ({ ...r }))
    } catch (e: any) {
      ElMessage.error(e?.message ?? t('page.configPage.saveFail'))
    } finally {
      savingIndex.value = false
    }
  }

  /** 奖励索引页：重置为本页数据（重新拉取列表） */
  function handleResetIndex() {
    loadIndexList()
    ElMessage.info(t('page.configPage.resetIndexReloaded'))
  }

  /** 大奖权重表单校验：点数在本表内不重复 */
  function validateBigwinFormForSave(): string | null {
    const rows = bigwinRows.value
    if (rows.length === 0) {
      return t('page.configPage.warnNoBigwinToSave')
    }
    const nums = rows.map((r) => Number(r.grid_number))
    const outOfRange = nums.filter(
      (n) => Number.isNaN(n) || n < GRID_NUMBER_MIN || n > GRID_NUMBER_MAX
    )
    if (outOfRange.length > 0) {
      return t('page.configPage.warnGridRange', { min: GRID_NUMBER_MIN, max: GRID_NUMBER_MAX })
    }
    const duplicates = findDuplicateValues(nums)
    if (duplicates.length > 0) {
      return t('page.configPage.warnBigwinDupGrid', {
        list: duplicates.join(t('page.configPage.dupJoiner'))
      })
    }
    return null
  }

  /** 大奖权重表单：提交 BIGWIN 的显示信息、英文、实际中奖、备注 + 权重（保存后后端会刷新缓存） */
  async function handleSaveBigwin() {
    const rows = bigwinRows.value
    if (rows.length === 0) {
      ElMessage.info(t('page.configPage.infoNoBigwin'))
      return
    }
    const err = validateBigwinFormForSave()
    if (err) {
      ElMessage.warning(err)
      return
    }
    savingBigwin.value = true
    try {
      const batchPayload = rows.map((r) => ({
        id: r.id,
        grid_number: r.grid_number,
        ui_text: r.ui_text,
        ui_text_en: r.ui_text_en,
        real_ev: r.real_ev,
        tier: 'BIGWIN',
        remark: r.remark
      }))
      await api.batchUpdate(batchPayload, { dept_id: filterDeptId.value })
      const weightItems = rows.map((r) => ({
        grid_number: r.grid_number,
        weight: isBigwinWeightDisabled(r)
          ? 10000
          : Math.max(0, Math.min(10000, Math.floor(r.weight)))
      }))
      await api.saveBigwinWeightsByGrid(weightItems, { dept_id: filterDeptId.value })
      ElMessage.success(t('page.configPage.saveSuccess'))
      loadIndexList()
    } catch (e: any) {
      ElMessage.error(e?.message ?? t('page.configPage.saveFail'))
    } finally {
      savingBigwin.value = false
    }
  }

  /** 大奖权重页：重置（重新拉取列表，BIGWIN 数据随之更新） */
  function handleResetBigwin() {
    loadIndexList()
    ElMessage.info(t('page.configPage.resetBigwinReloaded'))
  }

</script>

<style lang="scss" scoped>
  .reward-config-form {
    padding: 16px;
    height: 100%;
    display: flex;
    flex-direction: column;
    min-height: 0;
  }
  .form-card {
    margin-bottom: 16px;
    flex: 1;
    display: flex;
    flex-direction: column;
    min-height: 0;
    :deep(.el-card__body) {
      flex: 1;
      display: flex;
      flex-direction: column;
      min-height: 0;
      overflow: hidden;
    }
  }
  .card-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
  }
  .top-tabs {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-height: 0;
    :deep(.el-tabs__header) {
      margin-bottom: 12px;
      flex-shrink: 0;
    }
    :deep(.el-tabs__content) {
      flex: 1;
      min-height: 0;
      overflow: hidden;
    }
    :deep(.el-tab-pane) {
      height: 100%;
    }
  }
  .tab-panel {
    height: 100%;
    display: flex;
    flex-direction: column;
    min-height: 0;
  }
  .table-scroll-wrap {
    flex: 1;
    min-height: 0;
    overflow: auto;
    border: 1px solid var(--el-border-color-lighter);
    border-radius: 4px;
  }
  .tab-footer {
    flex-shrink: 0;
    margin-top: 12px;
    padding: 12px 0;
    border-top: 1px solid var(--el-border-color-lighter);
    display: flex;
    gap: 12px;
    background: var(--el-bg-color);
  }
  .panel-tip {
    font-size: 12px;
    color: var(--el-text-color-secondary);
    margin-bottom: 12px;
    line-height: 1.5;
  }
  .tier-recommend-panel {
    margin-bottom: 12px;
    padding: 12px 14px;
    background: var(--el-fill-color-light);
    border-radius: 8px;
    border: 1px solid var(--el-border-color-lighter);
    flex-shrink: 0;
  }
  .tier-recommend-rules {
    font-size: 12px;
    color: var(--el-text-color-secondary);
    line-height: 1.6;
    margin-bottom: 12px;
  }
  .tier-recommend-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 12px 20px;
    margin-bottom: 12px;
  }
  .tier-recommend-cell {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 8px;
    min-width: 140px;
    flex: 1 1 160px;
  }
  .tier-recommend-label {
    font-weight: 600;
    font-size: 13px;
    color: var(--el-text-color-primary);
    min-width: 28px;
  }
  .tier-recommend-hint {
    font-size: 12px;
    color: var(--el-text-color-secondary);
    white-space: nowrap;
  }
  .tier-recommend-input {
    width: 120px;
    flex: 1;
    min-width: 100px;
    max-width: 160px;
  }
  .tier-readonly {
    font-weight: 500;
    color: var(--el-text-color-primary);
  }
  .tier-recommend-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px 16px;
  }
  .index-toolbar {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    margin-bottom: 8px;
    flex-shrink: 0;
  }
  .rule-generate-dialog {
    :deep(.el-dialog__header) {
      padding: 12px 16px;
      margin-right: 0;
    }
    :deep(.el-dialog__body) {
      padding: 12px 16px 8px;
    }
    :deep(.el-dialog__footer) {
      padding: 12px 16px calc(16px + env(safe-area-inset-bottom, 0px));
    }
    .rule-generate-rules {
      font-size: 12px;
      color: var(--el-text-color-secondary);
      line-height: 1.65;
      white-space: pre-wrap;
      margin: 0 0 12px;
      padding: 12px;
      background: var(--el-fill-color-light);
      border-radius: 6px;
      max-height: min(260px, 38vh);
      overflow-y: auto;
      -webkit-overflow-scrolling: touch;
    }
    .rule-generate-form {
      margin-top: 4px;
      :deep(.el-form-item) {
        margin-bottom: 14px;
      }
      :deep(.el-form-item__label) {
        line-height: 1.4;
        align-items: flex-start;
      }
    }
    .rule-generate-scope {
      font-size: 12px;
      color: var(--el-text-color-secondary);
      margin: 8px 0 0;
      line-height: 1.5;
    }
    .rule-gen-row {
      display: flex;
      flex-wrap: wrap;
      align-items: flex-end;
      gap: 12px 20px;
      width: 100%;
    }
    .rule-gen-cell {
      display: flex;
      align-items: center;
      gap: 8px;
      flex: 1 1 200px;
      min-width: 0;
    }
    .rule-gen-hint {
      font-size: 12px;
      color: var(--el-text-color-secondary);
      white-space: nowrap;
      flex-shrink: 0;
    }
    .rule-gen-input-num {
      flex: 1;
      min-width: 0;
      width: 100%;
      max-width: 100%;
    }
    .rule-gen-input-num :deep(.el-input__wrapper) {
      min-height: 36px;
    }
    .rule-gen-footer-btns {
      display: flex;
      flex-wrap: wrap;
      justify-content: flex-end;
      gap: 10px;
      width: 100%;
    }
  }

  @media (max-width: 639px) {
    .rule-generate-dialog {
      :deep(.el-dialog) {
        margin: 0;
        max-height: 100%;
      }
      :deep(.el-dialog.is-fullscreen) {
        display: flex;
        flex-direction: column;
      }
      :deep(.el-dialog.is-fullscreen .el-dialog__body) {
        flex: 1;
        min-height: 0;
        overflow-y: auto;
        -webkit-overflow-scrolling: touch;
      }
      .rule-generate-rules {
        max-height: min(200px, 32vh);
        font-size: 11px;
      }
      .rule-gen-row {
        flex-direction: column;
        align-items: stretch;
        gap: 12px;
      }
      .rule-gen-cell {
        flex-direction: column;
        align-items: stretch;
        flex: none;
        width: 100%;
      }
      .rule-gen-hint {
        white-space: normal;
      }
      .rule-gen-input-num {
        width: 100%;
      }
      .rule-gen-input-num :deep(.el-input__wrapper) {
        min-height: 40px;
      }
      .rule-gen-footer-btns {
        flex-direction: column-reverse;
        align-items: stretch;
        .el-button {
          width: 100%;
          margin: 0;
        }
      }
    }
  }
  .config-table {
    width: 100%;
    .full-width {
      width: 100%;
    }
  }
  .weight-cell {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 0 8px;
    .el-slider {
      flex: 1;
    }
    .weight-input {
      width: 120px;
    }
  }
  .weight-tip {
    font-size: 12px;
    color: var(--el-text-color-secondary);
  }
  .readonly-value {
    font-weight: 500;
    color: var(--el-text-color-regular);
  }
  .bigwin-table .full-width {
    width: 100%;
  }
  .empty-tip {
    padding: 24px;
    text-align: center;
    color: var(--el-text-color-secondary);
  }
</style>
