<script setup lang="ts">
import { computed, nextTick, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { AgGridVue } from 'ag-grid-vue3'
import type { ColDef, ColGroupDef, GridApi, GridOptions, GridReadyEvent } from 'ag-grid-community'
import { getIndustryDisplayName, getMajorDictEntries, getServiceDictItemById, isMajorIdInIndustryScope } from '@/sql'
import { myTheme, gridOptions, agGridWrapClass, agGridStyle } from '@/lib/diyAgGridOptions'
import { decimalAggSum, roundTo, sumByNumber } from '@/lib/decimal'
import { formatThousandsFlexible } from '@/lib/numberFormat'
import { withReadonlyAutoHeight } from '@/lib/agGridReadonlyAutoHeight'
import { syncPricingTotalToZxFw } from '@/lib/zxFwPricingSync'
import { useZxFwPricingStore } from '@/pinia/zxFwPricing'
import { useKvStore } from '@/pinia/kv'
import { loadConsultCategoryFactorMap, loadMajorFactorMap } from '@/lib/xmFactorDefaults'
import { parseNumberOrNull } from '@/lib/number'
import {
  buildScaleDetailDict,
  buildScaleIdLabelMap,
  buildScaleRowsFromDict,
  type ScaleDictGroup
} from '@/lib/pricingScaleDict'
import {
  createScaleAutoGroupColumn,
  createScaleBenchmarkBudgetColumnGroup,
  createScaleBudgetFeeColumnGroup,
  createScaleCalculationFormulaColumnGroup,
  createScaleRemarkColumn,
  createScaleValueColumn
} from '@/lib/pricingScaleColumns'
import {
  createScaleBudgetCellRendererToggleFactory,
  formatScaleEditableConditionalNumber,
  formatScaleEditableNumber,
  formatScaleReadonlyMoney,
  restoreScaleColumnDefaults,
  type ScaleBudgetCheckField,
  type ScaleBudgetHeaderCheckState,
  ScaleBudgetToggleHeader,
} from '@/lib/pricingScaleGrid'
import {
  getCheckedBenchmarkBudgetSplitByRow,
  getScaleBudgetFeeByRow,
  getScaleBudgetFeeSplitByRow,
  isBenchmarkBudgetFullyUnchecked,
  isSameNullableNumber,
  recomputeScaleDetailRowsInPlace
} from '@/lib/pricingScaleDetail'
import { sumNullableBy } from '@/lib/pricingScaleCalc'
import { createPinnedTopRowData } from '@/lib/pricingPinnedRows'
import { usePricingPaneLifecycle } from '@/lib/pricingScalePaneLifecycle'
import {
  applyPricingScaleProjectCountChange,
  clearPricingScalePaneRows,
  importPricingScalePaneRows,
  loadPricingScalePaneRows
} from '@/lib/pricingScalePaneData'
import {
  buildScaleProjectGroupPathKey,
  buildScopedScaleRowId,
  getScaleProjectMajorKeyFromRow,
  inferScaleProjectCountFromRows,
  normalizeScaleProjectCount
} from '@/lib/pricingScaleProject'
import { mergeScaleRowsFromProjectMajorMap } from '@/lib/pricingScaleRowMap'
import { buildProjectScopedSessionKey } from '@/lib/pricingPersistControl'
import {
  buildContractScaleIdMap,
  buildContractScaleMap,
  buildContractScaleProjectTotals,
  getContractScaleRowByMajor,
  getContractScaleProjectTotalsByRow,
  makeProjectMajorKey,
  normalizeChangedScaleRowIds,
  parseProjectIndexFromPathKey,
  parseScopedRowId,
  resolveScaleRowMajorDictId as resolveRowMajorDictId,
  resolveScaleRowProjectIndex as resolveRowProjectIndex
} from '@/lib/pricingScaleLink'
import { AgGridResetHeader } from '@/lib/agGridResetHeader'
import { Button } from '@/components/ui/button'
import {
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogOverlay,
  AlertDialogPortal,
  AlertDialogRoot,
  NumberFieldDecrement,
  NumberFieldIncrement,
  NumberFieldInput,
  NumberFieldRoot,
  AlertDialogTitle,
  AlertDialogTrigger,
} from 'reka-ui'

import { AG_GRID_LOCALE_CN } from '@ag-grid-community/locale';
import {useDataStore} from "@/pinia/zx";
// 精简的边框配置（细线条+浅灰色，弱化分割线视觉）

interface DetailRow {
  id: string
  projectIndex?: number
  majorDictId?: string
  groupCode: string
  groupName: string
  majorCode: string
  majorName: string
  hasCost: boolean
  hasArea: boolean
  amount: number | null
  benchmarkBudget: number | null
  benchmarkBudgetBasic: number | null
  benchmarkBudgetOptional: number | null
  benchmarkBudgetBasicChecked: boolean
  benchmarkBudgetOptionalChecked: boolean
  basicFormula: string |null
  optionalFormula: string |null
  consultCategoryFactor: number | null
  majorFactor: number | null
  workStageFactor: number | string | null
  workRatio: number | string | null
  budgetFee: number | null
  budgetFeeBasic: number | null
  budgetFeeOptional: number | null
  serviceFee: number | null
  remark: string
  path: string[],
  base:string
}

interface XmInfoState {
  projectName: string
  detailRows: DetailRow[]
}
interface XmBaseInfoState {
  projectIndustry?: string
}

interface ContractScaleChangeState {
  changedRowIds?: string[]
  updatedAt?: number
}

interface FactorChangeState {
  changedRowIds?: string[]
  updatedAt?: number
}

interface ServiceLite {
  mutiple?: boolean | null
  onlyCostScale?: boolean | null
}

const props = defineProps<{
  contractId: string,
  serviceId: string | number
  projectInfoKey?: string
}>()
const zxFwPricingStore = useZxFwPricingStore()
const { t, locale } = useI18n()
const kvStore = useKvStore()
const DB_KEY = computed(() => `tzGMF-${props.contractId}-${props.serviceId}`)
const HT_DB_KEY = computed(() => `ht-info-v3-${props.contractId}`)
const HT_SCALE_CHANGE_KEY = computed(() => `ht-info-scale-change-v1-${props.contractId}`)
const HT_CONSULT_FACTOR_KEY = computed(() => `ht-consult-category-factor-v1-${props.contractId}`)
const HT_MAJOR_FACTOR_KEY = computed(() => `ht-major-factor-v1-${props.contractId}`)
const HT_CONSULT_FACTOR_CHANGE_KEY = computed(() => `${HT_CONSULT_FACTOR_KEY.value}-change`)
const HT_MAJOR_FACTOR_CHANGE_KEY = computed(() => `${HT_MAJOR_FACTOR_KEY.value}-change`)
const BASE_INFO_KEY = computed(() => props.projectInfoKey || 'xm-base-info-v1')
const activeIndustryCode = ref('')
const PRICING_CLEAR_SKIP_PREFIX = 'pricing-clear-skip:'
const PRICING_FORCE_DEFAULT_PREFIX = 'pricing-force-default:'
const consultCategoryFactorMap = ref<Map<string, number | null>>(new Map())
const majorFactorMap = ref<Map<string, number | null>>(new Map())
let factorDefaultsLoaded = false
const paneInstanceCreatedAt = Date.now()
const gridApi = ref<GridApi<DetailRow> | null>(null)
const lastAppliedConsultFactorChangeAt = ref(0)
const lastAppliedMajorFactorChangeAt = ref(0)
const ONLY_COST_SCALE_ROW_ID = '__only-cost-scale-total__'

const getDefaultConsultCategoryFactor = () =>
  consultCategoryFactorMap.value.get(String(props.serviceId)) ?? null

const getDefaultMajorFactorById = (id: string): number | null => majorFactorMap.value.get(id) ?? null
const isOnlyCostScaleService = computed(() => {
  const service = getServiceDictItemById(props.serviceId) as ServiceLite | undefined
  return service?.onlyCostScale === true
})
const isMutipleService = computed(() => {
  const service = getServiceDictItemById(props.serviceId) as ServiceLite | undefined
  return service?.mutiple === true
})
const projectCount = ref<number>(1)
const normalizeProjectCount = normalizeScaleProjectCount
const getTargetProjectCount = () => (isMutipleService.value ? normalizeProjectCount(projectCount.value) : 1)
const buildProjectGroupPathKey = (projectIndex: number) => buildScaleProjectGroupPathKey(projectIndex)
const buildScopedRowId = (projectIndex: number, majorId: string) =>
  buildScopedScaleRowId(isMutipleService.value, projectIndex, majorId)
const inferProjectCountFromRows = (rows?: Array<Partial<DetailRow>>) => {
  return inferScaleProjectCountFromRows(rows, isMutipleService.value)
}
const totalLabel = computed(() => {
  if (isOnlyCostScaleService.value) {
    const service = getServiceDictItemById(props.serviceId) as { code?: string; name?: string } | undefined
    return `${service?.code || ''} ${service?.name || ''}`.trim()
  }
  const industryName = getIndustryDisplayName(activeIndustryCode.value.trim(), locale.value)
  return industryName ? t('pricingScale.totalInvestmentByIndustry', { industryName }) : t('pricingScale.totalInvestment')
})

const loadFactorDefaults = async () => {
  const [consultMap, majorMap] = await Promise.all([
    loadConsultCategoryFactorMap(HT_CONSULT_FACTOR_KEY.value),
    loadMajorFactorMap(HT_MAJOR_FACTOR_KEY.value)
  ])
  consultCategoryFactorMap.value = consultMap
  majorFactorMap.value = majorMap
  factorDefaultsLoaded = true
}

const ensureFactorDefaultsLoaded = async () => {
  if (factorDefaultsLoaded) return
  await loadFactorDefaults()
}

const shouldSkipPersist = () => {
  const storageKey = buildProjectScopedSessionKey(PRICING_CLEAR_SKIP_PREFIX, DB_KEY.value)
  const raw = sessionStorage.getItem(storageKey)
  if (!raw) return false
  const now = Date.now()

  if (raw.includes(':')) {
    const [issuedRaw, untilRaw] = raw.split(':')
    const issuedAt = Number(issuedRaw)
    const skipUntil = Number(untilRaw)
    if (Number.isFinite(issuedAt) && Number.isFinite(skipUntil) && now <= skipUntil) {
      return paneInstanceCreatedAt <= issuedAt
    }
    sessionStorage.removeItem(storageKey)
    return false
  }

  const skipUntil = Number(raw)
  if (Number.isFinite(skipUntil) && now <= skipUntil) return true
  sessionStorage.removeItem(storageKey)
  return false
}

const shouldForceDefaultLoad = () => {
  const storageKey = buildProjectScopedSessionKey(PRICING_FORCE_DEFAULT_PREFIX, DB_KEY.value)
  const raw = sessionStorage.getItem(storageKey)
  if (!raw) return false
  const forceUntil = Number(raw)
  sessionStorage.removeItem(storageKey)
  return Number.isFinite(forceUntil) && Date.now() <= forceUntil
}

const getMethodState = () =>
  zxFwPricingStore.getServicePricingMethodState<DetailRow>(props.contractId, props.serviceId, 'investScale')

// 从咨询服务明细中获取数据
const c0Amount = ref<number | null>(null)

const loadC0Amount = async () => {
  try {
    // 直接从合同段规模信息中获取 C0 建设项目总费用
    const htScaleState = await kvStore.getItem<{ totalAmount?: number | null }>(HT_DB_KEY.value)

    if (typeof htScaleState?.totalAmount === 'number' && htScaleState.totalAmount > 0) {
      c0Amount.value = htScaleState.totalAmount
      return
    }
    
    // 回退：尝试从项目规模信息中获取
    const xmScaleState = await kvStore.getItem<{ totalAmount?: number | null }>('xm-info-v3')
    c0Amount.value = typeof xmScaleState?.totalAmount === 'number' ? xmScaleState.totalAmount : null
  } catch (e) {
    c0Amount.value = null
  }
}

const SERVICE_SCALE_RULES: Record<string, { limit: number; rate: number; baseAmount: number; base: string }[]> = {
  'D1': [
    { limit: 1000, rate: 1.32, baseAmount: 0, base: 'F<1000' },
    { limit: 10000, rate: 0.99, baseAmount: 13200, base: '1000≦F<10000' },
    { limit: 100000, rate: 0.83, baseAmount: 102900, base: '10000≦F<100000' },
    { limit: Infinity, rate: 0.66, baseAmount: 930900, base: 'F≧100000' }
  ],
  'D2-1': [
    { limit: 1000, rate: 0.67, baseAmount: 0, base: 'F<1000' },
    { limit: 10000, rate: 0.50, baseAmount: 6700, base: '1000≦F<10000' },
    { limit: 100000, rate: 0.42, baseAmount: 51700, base: '10000≦F<100000' },
    { limit: Infinity, rate: 0.33, baseAmount: 423700, base: 'F≧100000' }
  ],
  'D2-2-1': [
    { limit: 1000, rate: 0.73, baseAmount: 0, base: 'F<1000' },
    { limit: 10000, rate: 0.55, baseAmount: 7300, base: '1000≦F<10000' },
    { limit: 100000, rate: 0.46, baseAmount: 56800, base: '10000≦F<100000' },
    { limit: Infinity, rate: 0.37, baseAmount: 467800, base: 'F≧100000' }
  ],
  'D3-1': [
    { limit: 1000, rate: 0.13, baseAmount: 0, base: 'F<1000' },
    { limit: 10000, rate: 0.10, baseAmount: 1300, base: '1000≦F<10000' },
    { limit: 100000, rate: 0.08, baseAmount: 10300, base: '10000≦F<100000' },
    { limit: Infinity, rate: 0.07, baseAmount: 82300, base: 'F≧100000' }
  ],
  'D3-2': [
    { limit: 1000, rate: 0.26, baseAmount: 0, base: 'F<1000' },
    { limit: 10000, rate: 0.20, baseAmount: 26000, base: '1000≦F<10000' },
    { limit: 100000, rate: 0.17, baseAmount: 206000, base: '10000≦F<100000' },
    { limit: Infinity, rate: 0.13, baseAmount: 1646000, base: 'F≧100000' }
  ],
  'D3-3': [
    { limit: 1000, rate: 0.40, baseAmount: 0, base: 'F<1000' },
    { limit: 10000, rate: 0.30, baseAmount: 40000, base: '1000≦F<10000' },
    { limit: 100000, rate: 0.25, baseAmount: 310000, base: '10000≦F<100000' },
    { limit: Infinity, rate: 0.20, baseAmount: 2480000, base: 'F≧100000' }
  ],
  'D3-4': [
    { limit: 1000, rate: 0.24, baseAmount: 0, base: 'F<1000' },
    { limit: 10000, rate: 0.18, baseAmount: 24000, base: '1000≦F<10000' },
    { limit: 100000, rate: 0.15, baseAmount: 192000, base: '10000≦F<100000' },
    { limit: Infinity, rate: 0.12, baseAmount: 1542000, base: 'F≧100000' }
  ],
  'D3-6-1': [
    { limit: 1000, rate: 0.40, baseAmount: 0, base: 'F<1000' },
    { limit: 10000, rate: 0.30, baseAmount: 40000, base: '1000≦F<10000' },
    { limit: 100000, rate: 0.25, baseAmount: 310000, base: '10000≦F<100000' },
    { limit: Infinity, rate: 0.20, baseAmount: 2480000, base: 'F≧100000' }
  ],
  'D3-7': [
    { limit: 1000, rate: 1.00, baseAmount: 0, base: 'F<1000' },
    { limit: 10000, rate: 0.90, baseAmount: 100000, base: '1000≦F<10000' },
    { limit: 100000, rate: 0.80, baseAmount: 910000, base: '10000≦F<100000' },
    { limit: 500000, rate: 0.70, baseAmount: 8210000, base: '100000≦F<500000' },
    { limit: Infinity, rate: 0.60, baseAmount: 34210000, base: 'F≧500000' }
  ],
  'D4-6': [
    { limit: 1000, rate: 5.00, baseAmount: 0, base: 'F<1000' },
    { limit: 5000, rate: 3.50, baseAmount: 50000, base: '1000≦F<5000' },
    { limit: 10000, rate: 2.00, baseAmount: 190000, base: '5000≦F<10000' },
    { limit: 100000, rate: 1.00, baseAmount: 290000, base: '10000≦F<100000' },
    { limit: Infinity, rate: 0.80, baseAmount: 1090000, base: 'F≧100000' }
  ]
}

const calcServiceScaleAmount = (code: string, F: number): { formula: string; amount: number; base: string } => {
  if (F == null || F < 0) return { formula: '', amount: 0, base: '' }
  const rules = SERVICE_SCALE_RULES[code]
  if (!rules) return { formula: '无对应规则', amount: 0, base: '' }

  let prevLimit = 0
  for (let i = 0; i < rules.length; i++) {
    const { limit, rate, baseAmount, base } = rules[i]
    if (F < limit) {
      if (baseAmount === 0) {
        // 第一档：直接按比例计算
        const calculatedAmount = F * rate * 10000
        return {
          formula: `F×${rate}%`,
          amount: Math.round(calculatedAmount),
          base: base,
        }
      } else {
        // 后续档位：基础金额 + 超出部分按比例计算
        const calculatedAmount = baseAmount + (F - prevLimit) * rate * 10000
        return {
          formula: `${baseAmount.toLocaleString()}+(F-${prevLimit.toLocaleString()})×${rate}%`,
          amount: Math.round(calculatedAmount),
          base: base,
        }
      }
    }
    prevLimit = limit
  }
  return { formula: '', amount: 0, base: '' }
}

const calculateServiceFeeForRow = (row: DetailRow): number | null => {
  const budgetFee = typeof row.budgetFee === 'number' ? row.budgetFee : 0
  const workStageFactor = typeof row.workStageFactor === 'number' ? row.workStageFactor : 1
  const workRatio = typeof row.workRatio === 'number' ? row.workRatio : 1

  if (budgetFee === null) return null

  return Math.round(budgetFee * workStageFactor * workRatio)
}

// ✅ 批量重新计算所有行的 serviceFee
const recalculateServiceFees = () => {
  for (const row of fallbackDetailRows.value) {
    row.serviceFee = calculateServiceFeeForRow(row)
  }
}

const fallbackDetailRows = ref<DetailRow[]>([])
const detailRows = computed<DetailRow[]>({
  get: () => {
    return fallbackDetailRows.value;
    /*const contractState = zxFwPricingStore.contracts[props.contractId]
    if (!contractState?.detailRows) return []

    const F = c0Amount.value
    const isC0Available = F != null && F > 0

    // 获取当前的investScale状态，用于保持用户编辑的系数等
    const currentInvestScaleState = zxFwPricingStore.getServicePricingMethodState(
        props.contractId,
        props.serviceId,
        'investScale'
    )
    if (contractState.detailRows.length > 0) {
      const rowsToMap = contractState.detailRows.slice(0, -1)
      return rowsToMap.map(row => {
        const code = row.code || ''

        const { formula, amount, base } = isC0Available ? calcServiceScaleAmount(code, F) : { formula: '', amount: 0, base: '' }
        // 查找当前状态中对应的行，获取用户编辑过的值
        const currentDetailRow = currentInvestScaleState?.detailRows?.find(
            r => r.majorDictId === row.id
        )

        // 使用用户编辑的值，如果没有则使用默认值
        const workStageFactor = currentDetailRow?.workStageFactor ?? 1
        const workRatio = currentDetailRow?.workRatio ?? 1



        return {
          id: row.id || '',
          projectIndex: 1,
          majorDictId: row.id || '',
          groupCode: code,
          groupName: row.name || '',
          majorCode: code,
          majorName: row.name || '',
          hasCost: true,
          hasArea: false,
          amount: F,
          benchmarkBudget: isC0Available ? amount : null,
          benchmarkBudgetBasic: isC0Available ? amount : null,
          benchmarkBudgetOptional: isC0Available ? 0 : null,
          benchmarkBudgetBasicChecked: isC0Available ? true : true,
          benchmarkBudgetOptionalChecked: isC0Available ? false : true,
          basicFormula: isC0Available ? 'C0建设项目总费用' : '',
          optionalFormula: isC0Available ? formula : '',
          consultCategoryFactor: currentDetailRow?.consultCategoryFactor ?? null,
          majorFactor: currentDetailRow?.majorFactor ?? null,
          workStageFactor: workStageFactor,  // 使用用户编辑的值
          workRatio: workRatio,              // 使用用户编辑的值
          budgetFee: isC0Available ? amount : null,
          budgetFeeBasic: isC0Available ? amount : null,
          budgetFeeOptional: isC0Available ? 0 : null,
          serviceFee: isC0Available ? Math.round(amount * workStageFactor * workRatio / 100) : null,
          remark: row.remark || '',
          path: [code, row.id || ''],
          base: base,
          code: code
        }
      })
    }

    return []*/
  },
  set: rows => {
    saveToIndexedDB();
    fallbackDetailRows.value = rows
    /*// 将编辑后的视图数据转换回存储格式
    const investScaleDetailRows = []
    for (let i = 0; i < rows.length; i++) {
      const row = rows[i]
      investScaleDetailRows.push({
        majorDictId: row.majorDictId,
        consultCategoryFactor: row.consultCategoryFactor,
        majorFactor: row.majorFactor,
        workStageFactor: row.workStageFactor,
        workRatio: row.workRatio
      })
    }

    const currentState = getMethodState()
    zxFwPricingStore.setServicePricingMethodState(
        props.contractId,
        props.serviceId,
        'investScale',
        {
          detailRows: investScaleDetailRows,
          projectCount: currentState?.projectCount ?? getTargetProjectCount()
        }
    )*/
  }
})
type majorLite = {
  code: string
  name: string
  defCoe: number | null
  hasCost?: boolean
  hasArea?: boolean
  industryId?: string | number | null
}

const serviceEntries: Array<[string, majorLite]> = []
const detailDict: ScaleDictGroup[] = []
const idLabelMap = new Map<string, string>()
const rebuildScaleDictCaches = () => {
  const nextServiceEntries = getMajorDictEntries().map(({ id, item }) => [id, item] as [string, majorLite])
  serviceEntries.splice(0, serviceEntries.length, ...nextServiceEntries)
  const nextDetailDict = buildScaleDetailDict(
    serviceEntries,
    ({ hasCost, hasArea }) => hasCost && !hasArea
  )
  detailDict.splice(0, detailDict.length, ...nextDetailDict)
  const nextIdLabelMap = buildScaleIdLabelMap(nextDetailDict)
  idLabelMap.clear()
  nextIdLabelMap.forEach((label, id) => {
    idLabelMap.set(id, label)
  })
}
rebuildScaleDictCaches()

const buildDefaultRows = async (): Promise<DetailRow[]> => {
  const rows: DetailRow[] = []

  // ✅ 从 zxFw 数据获取专家列表
  const experts = await useDataStore().query([
    { field: 'type', value: `${props.contractId}-zxFw`, operator: 'eq' }
  ])

  // ✅ 为每个专家生成默认行
  for (const expert of experts) {
    const expertId = expert.id || expert._id
    const contractId = props.contractId
    const rowId = `${contractId}-investment-${expertId}`
    const code = expert.code || ''

    // ✅ 计算默认值
    const F = c0Amount.value
    const isC0Available = F != null && F > 0
    const { formula, amount, base } = isC0Available ? calcServiceScaleAmount(code, F) : { formula: '', amount: 0, base: '' }

    rows.push({
      id: rowId,
      projectIndex: 1,
      majorDictId: expertId || '',
      groupCode: code,
      groupName: expert.name || '',
      majorCode: code,
      majorName: expert.name || '',
      hasCost: true,
      hasArea: false,
      amount: F,
      benchmarkBudget: isC0Available ? amount : null,
      benchmarkBudgetBasic: isC0Available ? amount : null,
      benchmarkBudgetOptional: isC0Available ? 0 : null,
      benchmarkBudgetBasicChecked: true,
      benchmarkBudgetOptionalChecked: false,
      basicFormula: isC0Available ? 'C0建设项目总费用' : '',
      optionalFormula: isC0Available ? formula : '',
      consultCategoryFactor: null,
      majorFactor: null,
      workStageFactor: 1,        // ✅ 默认值
      workRatio: 1,            // ✅ 默认值
      budgetFee: isC0Available ? amount : null,
      budgetFeeBasic: isC0Available ? amount : null,
      budgetFeeOptional: isC0Available ? 0 : null,
      serviceFee: isC0Available ? Math.round(amount * 1) : null,
      remark: expert.remark || '',
      path: [code, expertId || ''],
      base: base,
      code: code
    })
  }

  return rows
}

const calcOnlyCostScaleAmountFromRows = (
  rows?: Array<{ amount?: unknown; isGroupRow?: unknown }>,
  totalAmount?: number | null
) => {
  if (typeof totalAmount === 'number' && Number.isFinite(totalAmount)) return totalAmount
  const summaryRow = (rows || []).find(row => row?.isGroupRow === true)
  if (typeof summaryRow?.amount === 'number' && Number.isFinite(summaryRow.amount)) return summaryRow.amount
  return sumByNumber(rows || [], row => (typeof row?.amount === 'number' ? row.amount : null))
}

const getOnlyCostScaleMajorEntry = () => {
  const industryId = String(activeIndustryCode.value || '').trim()
  if (!industryId) return null
  const industryMajor = serviceEntries.find(([, item]) => {
    const majorIndustryId = String(item?.industryId ?? '').trim()
    return majorIndustryId === industryId && !String(item?.code || '').includes('-')
  })
  if (!industryMajor) return null
  const [id, item] = industryMajor
  return { id, item }
}

const getOnlyCostScaleMajorFactorDefault = () => {
  const industryMajor = getOnlyCostScaleMajorEntry()
  if (!industryMajor) return 1
  const majorId = industryMajor.id
  const majorItem = industryMajor.item
  const fromMap = majorFactorMap.value.get(String(majorId))
  if (typeof fromMap === 'number' && Number.isFinite(fromMap)) return fromMap
  if (typeof majorItem?.defCoe === 'number' && Number.isFinite(majorItem.defCoe)) return majorItem.defCoe
  return 1
}

const buildOnlyCostScaleRow = (
  amount: number | null,
  projectIndex: number,
  fromDb?: Partial<
    Pick<
      DetailRow,
      | 'consultCategoryFactor'
      | 'majorFactor'
      | 'workStageFactor'
      | 'workRatio'
      | 'remark'
      | 'benchmarkBudgetBasicChecked'
      | 'benchmarkBudgetOptionalChecked'
    >
  >
): DetailRow => {
  const service = getServiceDictItemById(props.serviceId) as { code?: string; name?: string } | undefined
  const serviceCode = service?.code || 'D1'
  const serviceName = service?.name || '全过程造价咨询'
  return {
    id: buildScopedRowId(projectIndex, getOnlyCostScaleMajorEntry()?.id || ONLY_COST_SCALE_ROW_ID),
    projectIndex,
    majorDictId: getOnlyCostScaleMajorEntry()?.id || ONLY_COST_SCALE_ROW_ID,
    groupCode: serviceCode,
    groupName: serviceName,
    majorCode: serviceCode,
    majorName: serviceName,
    hasCost: true,
    hasArea: false,
    amount,
    benchmarkBudget: null,
    benchmarkBudgetBasic: null,
    benchmarkBudgetOptional: null,
    benchmarkBudgetBasicChecked:
      typeof fromDb?.benchmarkBudgetBasicChecked === 'boolean' ? fromDb.benchmarkBudgetBasicChecked : true,
    benchmarkBudgetOptionalChecked:
      typeof fromDb?.benchmarkBudgetOptionalChecked === 'boolean' ? fromDb.benchmarkBudgetOptionalChecked : true,
    basicFormula: '',
    optionalFormula: '',
    consultCategoryFactor:
      typeof fromDb?.consultCategoryFactor === 'number' ? fromDb.consultCategoryFactor : getDefaultConsultCategoryFactor(),
    majorFactor: typeof fromDb?.majorFactor === 'number' ? fromDb.majorFactor : getOnlyCostScaleMajorFactorDefault(),
    workStageFactor: typeof fromDb?.workStageFactor === 'number' ? fromDb.workStageFactor : 1,
    workRatio: typeof fromDb?.workRatio === 'number' ? fromDb.workRatio : 100,
    budgetFee: null,
    budgetFeeBasic: null,
    budgetFeeOptional: null,
    remark: typeof fromDb?.remark === 'string' ? fromDb.remark : '',
    path: isMutipleService.value
      ? [buildProjectGroupPathKey(projectIndex), buildScopedRowId(projectIndex, getOnlyCostScaleMajorEntry()?.id || ONLY_COST_SCALE_ROW_ID)]
      : [buildScopedRowId(projectIndex, getOnlyCostScaleMajorEntry()?.id || ONLY_COST_SCALE_ROW_ID)]
  }
}

const buildOnlyCostScaleRows = (
  rowsFromDb?: Array<Partial<DetailRow> & Pick<DetailRow, 'id'>>,
  options?: {
    projectCount?: number
    cloneFromProjectOne?: boolean
    totalAmount?: number | null
    preferSummaryAmountWhenSingleRow?: boolean
  }
): DetailRow[] => {
  const targetProjectCount = normalizeProjectCount(options?.projectCount ?? getTargetProjectCount())
  const onlyCostMajorId = getOnlyCostScaleMajorEntry()?.id || ONLY_COST_SCALE_ROW_ID
  const singleRowSummaryAmount =
    options?.preferSummaryAmountWhenSingleRow
      ? calcOnlyCostScaleAmountFromRows(
          rowsFromDb as Array<{ amount?: unknown; isGroupRow?: unknown }>,
          options.totalAmount
        )
      : null
  const dbValueMap = new Map<string, Partial<DetailRow> & Pick<DetailRow, 'id'>>()
  for (const row of rowsFromDb || []) {
    const projectIndex = resolveRowProjectIndex(row)
    const majorDictId = resolveRowMajorDictId(row) || onlyCostMajorId
    dbValueMap.set(makeProjectMajorKey(projectIndex, majorDictId), row)
    if (String(row.id || '') === ONLY_COST_SCALE_ROW_ID && !dbValueMap.has(makeProjectMajorKey(projectIndex, onlyCostMajorId))) {
      dbValueMap.set(makeProjectMajorKey(projectIndex, onlyCostMajorId), row)
    }
  }

  const result: DetailRow[] = []
  for (let projectIndex = 1; projectIndex <= targetProjectCount; projectIndex++) {
    const key = makeProjectMajorKey(projectIndex, onlyCostMajorId)
    const firstProjectKey = makeProjectMajorKey(1, onlyCostMajorId)
    const fromDb =
      dbValueMap.get(key) ||
      (options?.cloneFromProjectOne && projectIndex > 1 ? dbValueMap.get(firstProjectKey) : undefined)
    const fallbackAmount =
      options?.cloneFromProjectOne && projectIndex > 1 && fromDb == null
        ? calcOnlyCostScaleAmountFromRows(rowsFromDb as Array<{ amount?: unknown; isGroupRow?: unknown }>, options.totalAmount)
        : null
    result.push(
      buildOnlyCostScaleRow(
        singleRowSummaryAmount ?? (typeof fromDb?.amount === 'number' ? fromDb.amount : fallbackAmount),
        projectIndex,
        fromDb
      )
    )
  }

  return result
}

type SourceRow = Pick<DetailRow, 'id'> &
    Partial<
        Pick<
            DetailRow,
            | 'projectIndex'
            | 'majorDictId'
            | 'amount'
            | 'benchmarkBudget'
            | 'benchmarkBudgetBasic'
            | 'benchmarkBudgetOptional'
            | 'benchmarkBudgetBasicChecked'
            | 'benchmarkBudgetOptionalChecked'
            | 'basicFormula'
            | 'optionalFormula'
            | 'consultCategoryFactor'
            | 'majorFactor'
            | 'workStageFactor'
            | 'workRatio'
            | 'budgetFee'
            | 'budgetFeeBasic'
            | 'budgetFeeOptional'
            | 'remark'
            >
        >

const mergeWithDictRows = async (rowsFromDb: DetailRow[]): Promise<DetailRow[]> => {
  const dbValueMap = new Map<string, DetailRow>()

  // ✅ 构建数据库数据映射
  for (const row of rowsFromDb) {
    dbValueMap.set(row.id, row)
  }

  // ✅ 获取默认行
  const defaultRows = await buildDefaultRows()

  // ✅ 合并数据库数据和默认数据
  return defaultRows.map(row => {
    const fromDb = dbValueMap.get(row.id)
    if (!fromDb) return row

    // ✅ 保留数据库中的所有可编辑字段
    return {
      ...row,
      // 可编辑字段从数据库加载
      serviceFee: typeof fromDb.serviceFee === 'number' ? fromDb.serviceFee : row.serviceFee,
      consultCategoryFactor: typeof fromDb.consultCategoryFactor === 'number' ? fromDb.consultCategoryFactor : null,
      majorFactor: typeof fromDb.majorFactor === 'number' ? fromDb.majorFactor : null,
      workStageFactor: typeof fromDb.workStageFactor === 'number' ? fromDb.workStageFactor : 1,
      workRatio: typeof fromDb.workRatio === 'number' ? fromDb.workRatio : 1,
      remark: typeof fromDb.remark === 'string' ? fromDb.remark : ''
    }
  })
}
/*const mergeWithDictRows = (
    rowsFromDb: SourceRow[] | undefined,
    options?: {
      includeAmount?: boolean
      includeFactorValues?: boolean
      projectCount?: number
      cloneFromProjectOne?: boolean
    }
): DetailRow[] => {
  const includeAmount = options?.includeAmount ?? true
  const includeFactorValues = options?.includeFactorValues ?? true
  const targetProjectCount = normalizeProjectCount(options?.projectCount ?? getTargetProjectCount())
  return mergeScaleRowsFromProjectMajorMap({
    rowsFromDb,
    projectCount: targetProjectCount,
    buildDefaultRows,
    resolveProjectIndex: row => resolveRowProjectIndex(row),
    resolveMajorDictId: row => resolveRowMajorDictId(row),
    cloneFromProjectOne: options?.cloneFromProjectOne,
    mergeRow: (row, fromDb) => {
      if (!fromDb) return row
      const nextMajorDictId = resolveRowMajorDictId(row)
      const hasConsultCategoryFactor = Object.prototype.hasOwnProperty.call(fromDb, 'consultCategoryFactor')
      const hasMajorFactor = Object.prototype.hasOwnProperty.call(fromDb, 'majorFactor')
      return {
        ...row,
        amount: includeAmount && row.hasCost && typeof fromDb.amount === 'number' ? fromDb.amount : null,
        benchmarkBudget: typeof fromDb.benchmarkBudget === 'number' ? fromDb.benchmarkBudget : null,
        benchmarkBudgetBasic: typeof fromDb.benchmarkBudgetBasic === 'number' ? fromDb.benchmarkBudgetBasic : null,
        benchmarkBudgetOptional: typeof fromDb.benchmarkBudgetOptional === 'number' ? fromDb.benchmarkBudgetOptional : null,
        benchmarkBudgetBasicChecked:
            typeof fromDb.benchmarkBudgetBasicChecked === 'boolean' ? fromDb.benchmarkBudgetBasicChecked : true,
        benchmarkBudgetOptionalChecked:
            typeof fromDb.benchmarkBudgetOptionalChecked === 'boolean' ? fromDb.benchmarkBudgetOptionalChecked : true,
        basicFormula: typeof fromDb.basicFormula === 'string' ? fromDb.basicFormula : '',
        optionalFormula: typeof fromDb.optionalFormula === 'string' ? fromDb.optionalFormula : '',
        consultCategoryFactor:
            !includeFactorValues
                ? null
                : typeof fromDb.consultCategoryFactor === 'number'
                ? fromDb.consultCategoryFactor
                : hasConsultCategoryFactor
                    ? null
                    : getDefaultConsultCategoryFactor(),
        majorFactor:
            !includeFactorValues
                ? null
                : typeof fromDb.majorFactor === 'number'
                ? fromDb.majorFactor
                : hasMajorFactor
                    ? null
                    : getDefaultMajorFactorById(nextMajorDictId),
        workStageFactor: typeof fromDb.workStageFactor === 'number' ? fromDb.workStageFactor : row.workStageFactor,
        workRatio: typeof fromDb.workRatio === 'number' ? fromDb.workRatio : row.workRatio,
        budgetFee: typeof fromDb.budgetFee === 'number' ? fromDb.budgetFee : null,
        budgetFeeBasic: typeof fromDb.budgetFeeBasic === 'number' ? fromDb.budgetFeeBasic : null,
        budgetFeeOptional: typeof fromDb.budgetFeeOptional === 'number' ? fromDb.budgetFeeOptional : null,
        remark: typeof fromDb.remark === 'string' ? fromDb.remark : ''
      }
    }
  })
}*/


const formatEditableMoney = (params: any) =>
  formatScaleEditableConditionalNumber(params, {
    enabled: Boolean(params.data?.hasCost),
    precision: 3,
    emptyText: t('pricingScale.clickToInput')
  })

const createBudgetCellRendererWithCheck = createScaleBudgetCellRendererToggleFactory(
  () => detailRows.value,
  () => handleCellValueChanged()
)

const getBenchmarkBudgetHeaderCheckState = (field: ScaleBudgetCheckField): ScaleBudgetHeaderCheckState => {
  const targetRows = detailRows.value.filter(row => row.hasCost)
  if (!targetRows.length) return 'all'
  const checkedCount = targetRows.reduce((count, row) => (row[field] !== false ? count + 1 : count), 0)
  if (checkedCount === 0) return 'none'
  if (checkedCount === targetRows.length) return 'all'
  return 'partial'
}

const toggleBenchmarkBudgetColumnChecked = (field: ScaleBudgetCheckField, checked: boolean) => {
  const targetRows = detailRows.value.filter(row => row.hasCost)
  if (!targetRows.length) return
  for (const row of targetRows) {
    row[field] = checked
  }
  gridApi.value?.refreshHeader()
  gridApi.value?.refreshCells({ force: true })
  handleCellValueChanged()
}

const getBenchmarkBudgetHeaderParams = (field: ScaleBudgetCheckField) => ({
  field,
  getHeaderCheckState: getBenchmarkBudgetHeaderCheckState,
  onToggleAll: toggleBenchmarkBudgetColumnChecked
})

const getBenchmarkBudgetSplitByAmount = (row?: Pick<DetailRow, 'amount'>) =>
  getCheckedBenchmarkBudgetSplitByRow(
    {
      amount: row?.amount,
      benchmarkBudgetBasicChecked: true,
      benchmarkBudgetOptionalChecked: true
    },
    'cost'
  )

const getCheckedBenchmarkBudgetSplitByAmount = (
  row?: Pick<DetailRow, 'amount' | 'benchmarkBudgetBasicChecked' | 'benchmarkBudgetOptionalChecked'>
) => getCheckedBenchmarkBudgetSplitByRow(row, 'cost')

const getBudgetFee = (
  row?: Pick<
    DetailRow,
    | 'amount'
    | 'benchmarkBudgetBasicChecked'
    | 'benchmarkBudgetOptionalChecked'
    | 'majorFactor'
    | 'consultCategoryFactor'
    | 'workStageFactor'
    | 'workRatio'
  >
) => getScaleBudgetFeeByRow(row, 'cost')

/**
 * 计算服务费用：计算金额 × 工作环节系数 × 工作占比 / 100
 * @param row 数据行对象，包含 benchmarkBudget、workStageFactor、workRatio 字段
 * @returns 四舍五入后的服务费用（元）
 */
const getServiceFee = (row?: Pick<DetailRow, 'benchmarkBudget' | 'workStageFactor' | 'workRatio'>) => {
  const budget = typeof row?.benchmarkBudget === 'number' ? row.benchmarkBudget : null
  const workStageFactor = typeof row?.workStageFactor === 'number' ? row.workStageFactor : 1
  const workRatio = typeof row?.workRatio === 'number' ? row.workRatio : 1
  
  if (budget == null) return null
  return Math.round(budget * workStageFactor * workRatio * 10000)
}

const getBudgetFeeSplit = (
    row?: Pick<
        DetailRow,
        | 'amount'
        | 'benchmarkBudgetBasicChecked'
        | 'benchmarkBudgetOptionalChecked'
        | 'majorFactor'
        | 'consultCategoryFactor'
        | 'workStageFactor'
        | 'workRatio'
        >
) => getScaleBudgetFeeSplitByRow(row, 'cost')

const restoreAmountColumnDefaults = async () => {
  const htData = await kvStore.getItem<{ detailRows: SourceRow[]; totalAmount?: number | null }>(HT_DB_KEY.value)
  const sourceRows = Array.isArray(htData?.detailRows) ? htData.detailRows : []
  const sourceRowMap = buildContractScaleMap(sourceRows)
  const sourceRowIdMap = buildContractScaleIdMap(sourceRows)
  const projectTotals = buildContractScaleProjectTotals(sourceRows, htData?.totalAmount)
  const useSummaryAmount = detailRows.value.length === 1 || isOnlyCostScaleService.value
  const onlyCostScaleFallbackAmount = isOnlyCostScaleService.value
      ? calcOnlyCostScaleAmountFromRows(sourceRows as Array<{ amount?: unknown; isGroupRow?: unknown }>, htData?.totalAmount)
      : null
  await restoreScaleColumnDefaults({
    gridApi: gridApi.value,
    rows: detailRows.value,
    getCurrentValue: row => row.amount,
    getNextValue: row => {
      if (!row.hasCost) return null
      if (useSummaryAmount) return getContractScaleProjectTotalsByRow(row, projectTotals).amount
      const sourceRow = getContractScaleRowByMajor(row, sourceRowMap, sourceRowIdMap)
      return typeof sourceRow?.amount === 'number' ? sourceRow.amount : onlyCostScaleFallbackAmount
    },
    isSameValue: isSameNullableNumber,
    applyValue: (row, nextValue) => {
      row.amount = nextValue
    },
    afterApply: async () => {
      syncComputedValuesToDetailRows()
      await saveToIndexedDB({ skipComputedSync: true })
    }
  })
}

const restoreConsultCategoryFactorColumnDefaults = async () => {
  await loadFactorDefaults()
  const nextConsultFactor = getDefaultConsultCategoryFactor()
  await restoreScaleColumnDefaults({
    gridApi: gridApi.value,
    rows: detailRows.value,
    getCurrentValue: row => row.consultCategoryFactor,
    getNextValue: () => nextConsultFactor,
    isSameValue: isSameNullableNumber,
    applyValue: (row, nextValue) => {
      row.consultCategoryFactor = nextValue
    },
    afterApply: async () => {
      syncComputedValuesToDetailRows()
      await saveToIndexedDB({ skipComputedSync: true })
    }
  })
}

const restoreMajorFactorColumnDefaults = async () => {
  await loadFactorDefaults()
  await restoreScaleColumnDefaults({
    gridApi: gridApi.value,
    rows: detailRows.value,
    getCurrentValue: row => row.majorFactor,
    getNextValue: row => getDefaultMajorFactorById(resolveRowMajorDictId(row)),
    isSameValue: isSameNullableNumber,
    applyValue: (row, nextValue) => {
      row.majorFactor = nextValue
    },
    afterApply: async () => {
      syncComputedValuesToDetailRows()
      await saveToIndexedDB({ skipComputedSync: true })
    }
  })
}

const columnDefs: Array<ColDef<DetailRow> | ColGroupDef<DetailRow>> = [
  {
    headerName: t('pricingScale.columns.name'),
    field: 'majorName',
    minWidth: 150,
    flex: 1.5,
    wrapText: true,
    autoHeight: true,
    cellStyle: { whiteSpace: 'normal', lineHeight: '1.4' },
    valueFormatter: params => {
      if (params.node?.rowPinned) return ''
      return params.value || ''
    }
  },
  {
    headerName: t('pricingScale.columns.base'),
    field: 'amount',
    minWidth: 120,
    flex: 1,
    editable: false,
    wrapText: true,
    autoHeight: true,
    cellStyle: { whiteSpace: 'normal', lineHeight: '1.4' },
    valueFormatter: params => params.value || ''
  },
  {
    headerName: t('pricingScale.columns.base2'),
    field: 'base',
    headerClass: 'ag-right-aligned-header',
    minWidth: 130,
    flex: 1,
    editable: false,
    cellClassRules: {
      'ag-right-aligned-cell': () => true
    },
    valueFormatter: params => {
      const value = params.value
      if (value == null) return ''
      return typeof value === 'number' ? value.toLocaleString() : String(value)
    }
  },
  {
    headerName: t('pricingScale.columns.formula'),
    field: 'optionalFormula',
    minWidth: 200,
    flex: 1.5,
    editable: false,
    wrapText: true,
    autoHeight: true,
    cellStyle: { whiteSpace: 'normal', lineHeight: '1.4' },
    valueFormatter: params => params.value || ''
  },
  {
    headerName: t('pricingScale.columns.calculationAmount'),
    field: 'budgetFee',
    headerClass: 'ag-right-aligned-header',
    minWidth: 120,
    flex: 1,
    editable: false,
    cellClassRules: {
      'ag-right-aligned-cell': () => true
    },
    // valueFormatter: params => {
    //   const value = params.value
    //   if (value == null) return ''
    //   // 结果乘 10000 后格式化显示
    //   const scaledValue = typeof value === 'number' ? value * 10000 : null
    //   if (scaledValue == null) return ''
    //   return scaledValue.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })
    // }
  },
  {
    headerName: '本计算取值',
    marryChildren: true,
    children: [
      {
        headerName: t('pricingScale.columns.workStageFactor'),
        field: 'workStageFactor',
        headerClass: 'ag-right-aligned-header',
        minWidth: 80,
        flex: 1,
        editable: params => !params.node?.group && !params.node?.rowPinned,
        cellClass: params =>
          !params.node?.group && !params.node?.rowPinned
            ? 'editable-cell-line'
            : '',
        cellClassRules: {
          'ag-right-aligned-cell': () => true,
          'editable-cell-empty': params =>
            !params.node?.group && !params.node?.rowPinned && (params.value == null || params.value === '')
        },
        valueParser: params => parseNumberOrNull(params.newValue, { precision: 3 }),
        valueFormatter: (params) => {
          if (params.node?.rowPinned === 'bottom') {
            return '/'
          }
          return formatScaleEditableNumber(params)
        }
      },
      {
        headerName: t('pricingScale.columns.workRatio'),
        field: 'workRatio',
        headerClass: 'ag-right-aligned-header',
        minWidth: 80,
        flex: 1,
        editable: params => !params.node?.group && !params.node?.rowPinned,
        cellClass: params =>
          !params.node?.group && !params.node?.rowPinned
            ? 'editable-cell-line'
            : '',
        cellClassRules: {
          'ag-right-aligned-cell': () => true,
          'editable-cell-empty': params =>
            !params.node?.group && !params.node?.rowPinned && (params.value == null || params.value === '')
        },
        valueParser: params => parseNumberOrNull(params.newValue, { precision: 2 }),
        valueFormatter: (params) => {
          if (params.node?.rowPinned === 'bottom') {
            return '/'
          }
          return formatScaleEditableNumber(params, 2)
        }
      },
      {
        headerName: t('pricingScale.columns.serviceFee'),
        field: 'serviceFee',
        colId: 'serviceFeeTotal',
        headerClass: 'ag-right-aligned-header',
        minWidth: 120,
        flex: 1,
        aggFunc: decimalAggSum,
        cellClassRules: {
          'ag-right-aligned-cell': () => true
        },
        /*valueGetter: (params) => {
          // ✅ 使用字符串字面量作为字段名
          const workStageFactorValue = params.data?.['workStageFactor'] ?? 0;
          const workRatioValue = params.data?.['workRatio'] ?? 0;
          const budgetFeeValue = params.data?.['budgetFee'] ?? 0;

          const subtotal = workRatioValue * workStageFactorValue * budgetFeeValue;

          if (params.node?.rowPinned === 'bottom') {
            // 计算总计
            const allRows = fallbackDetailRows.value;
            const total = allRows.reduce((sum, row) => {
              return sum + (
                  (row['workStageFactor'] as number || 0) *
                  (row['workRatio'] as number || 0) *
                  (row['budgetFee'] as number || 0)
              );
            }, 0);
            return Math.round(total);
          }

          return Math.round(subtotal);
        },*/
        // valueGetter: params => (params.node?.rowPinned ? (params.data as any)?.serviceFee ?? null : getServiceFee(params.data)),
        valueFormatter: formatScaleReadonlyMoney
      }
    ]
  },
  {
    headerName: t('pricingScale.columns.remark'),
    field: 'remark',
    minWidth: 100,
    flex: 1.2,
    cellEditor: 'agLargeTextCellEditor',
    wrapText: true,
    autoHeight: true,
    cellStyle: { whiteSpace: 'normal', lineHeight: '1.4' },
    editable: params => !params.node?.group && !params.node?.rowPinned,
    valueFormatter: params => {
      if (!params.node?.group && !params.node?.rowPinned && !params.value) return t('pricingScale.clickToInput')
      return params.value || ''
    },
    cellClass: params => (!params.node?.group && !params.node?.rowPinned ? ' remark-wrap-cell' : ''),
    cellClassRules: {
      'editable-cell-empty': params =>
        !params.node?.group && !params.node?.rowPinned && (params.value == null || params.value === '')
    }
  }
]
const gridColumnDefs = computed(() => withReadonlyAutoHeight(columnDefs))

const autoGroupColumnDef: ColDef = {
  headerName: t('pricingScale.columns.number'),
  minWidth: 80,
  flex: 2,
  wrapText: true,
  autoHeight: true,
  cellStyle: {
    whiteSpace: 'normal',
    lineHeight: '1.4'
  },
  // 不使用默认的分组渲染器，避免显示折叠箭头
  cellRenderer: undefined,
  colSpan: params => {
    // 如果是固定行（小计行），跨越 2 列
    if (params.node?.rowPinned || params.data?.id === 'pinned-total-row') {
      return 2
    }
    return 1
  },
  valueFormatter: params => {
    if (params.node?.rowPinned) {
      return '小计'
    }
    const rowData = params.data as any
    // 直接显示编码和名称
    if (rowData?.majorCode) {
      return `${rowData.majorCode}`
    }
    return params.value || ''
  },
  tooltipValueGetter: params => {
    if (params.node?.rowPinned) return totalLabel.value
    const rowData = params.data as any
    if (rowData?.majorCode && rowData?.majorName) {
      return `${rowData.majorCode} ${rowData.majorName}`
    }
    return params.value || ''
  }
}

// const totalBudgetFee = computed(() => sumNullableBy(detailRows.value, row => getBudgetFee(row)))
const totalBudgetFee = computed(() => sumNullableBy(detailRows.value, row => row.budgetFee))
const totalBudgetFeeBasic = computed(() => sumNullableBy(detailRows.value, row => getBudgetFeeSplit(row)?.basic))
const totalBudgetFeeOptional = computed(() => sumNullableBy(detailRows.value, row => getBudgetFeeSplit(row)?.optional))
const totalServiceFee = computed(() => sumNullableBy(detailRows.value, row => row.serviceFee))
const pinnedTopRowData = computed(() => [
  {
    id: 'pinned-total-row',
    groupCode: '',
    groupName: '',
    majorCode: '',
    majorName: totalLabel.value,
    base: '/',
    hasCost: false,
    hasArea: false,
    amount: '/',
    benchmarkBudget: null,
    benchmarkBudgetBasic: null,
    benchmarkBudgetOptional: null,
    benchmarkBudgetBasicChecked: true,
    benchmarkBudgetOptionalChecked: true,
    basicFormula: '/',
    optionalFormula: '/',
    workStageFactor: '/',
    workRatio: '/',
    consultCategoryFactor: null,
    majorFactor: null,
    budgetFee: totalBudgetFee.value,
    budgetFeeBasic: totalBudgetFeeBasic.value,
    budgetFeeOptional: totalBudgetFeeOptional.value,
    serviceFee: totalServiceFee.value,
    remark: '',
    path: ['TOTAL']
  }
])

const syncComputedValuesToDetailRows = () => {
  recomputeScaleDetailRowsInPlace(detailRows.value, 'cost')
}

const buildPersistDetailRows = () => detailRows.value.map(row => ({ ...row }))

const saveToIndexedDB = async (options?: { skipComputedSync?: boolean }) => {
  const rows = fallbackDetailRows.value.map(row => ({ ...row, type: `${props.contractId}-investment` }))
  const stats = await useDataStore().upsertBatch(rows)
  console.log('💾 数据保存成功:', stats)

  /*if (shouldSkipPersist()) return
  try {
    if (!options?.skipComputedSync) {
      syncComputedValuesToDetailRows()
    }
    const payload = {
      detailRows: JSON.parse(JSON.stringify(buildPersistDetailRows())),
      projectCount: getTargetProjectCount()
    }
    zxFwPricingStore.setServicePricingMethodState(
      props.contractId,
      props.serviceId,
      'investScale',
      payload,
      { force: true }
    )
    console.log(totalBudgetFee.value)
    const synced = await syncPricingTotalToZxFw({
      contractId: props.contractId,
      serviceId: props.serviceId,
      field: 'investScale',
      value: totalBudgetFee.value
    })
    if (!synced) return
  } catch (error) {
    console.error('saveToIndexedDB failed:', error)
  }*/
}

const syncLinkedFieldsFromContractAndFactors = async () => {
  /*if (detailRows.value.length === 0) return
  const consultChangeState =
    (zxFwPricingStore.keyedStates[HT_CONSULT_FACTOR_CHANGE_KEY.value]
      ?? kvStore.entries[HT_CONSULT_FACTOR_CHANGE_KEY.value]
      ?? null) as FactorChangeState | null
  const majorChangeState =
    (zxFwPricingStore.keyedStates[HT_MAJOR_FACTOR_CHANGE_KEY.value]
      ?? kvStore.entries[HT_MAJOR_FACTOR_CHANGE_KEY.value]
      ?? null) as FactorChangeState | null

  const consultUpdatedAt = Number(consultChangeState?.updatedAt)
  const majorUpdatedAt = Number(majorChangeState?.updatedAt)
  const hasNewConsultChange = Number.isFinite(consultUpdatedAt) && consultUpdatedAt > lastAppliedConsultFactorChangeAt.value
  const hasNewMajorChange = Number.isFinite(majorUpdatedAt) && majorUpdatedAt > lastAppliedMajorFactorChangeAt.value

  const consultChangedRowIds = new Set(
    (consultChangeState?.changedRowIds || []).map(id => String(id || '').trim()).filter(Boolean)
  )
  const majorChangedRowIdSet = normalizeChangedScaleRowIds(majorChangeState?.changedRowIds)
  const shouldSyncConsultFactor = hasNewConsultChange && consultChangedRowIds.has(String(props.serviceId).trim())
  const shouldSyncMajorFactor = hasNewMajorChange && majorChangedRowIdSet.size > 0

  if (hasNewConsultChange) lastAppliedConsultFactorChangeAt.value = consultUpdatedAt
  if (hasNewMajorChange) lastAppliedMajorFactorChangeAt.value = majorUpdatedAt
  if (!shouldSyncConsultFactor && !shouldSyncMajorFactor) return

  await loadFactorDefaults()
  const consultFactor = getDefaultConsultCategoryFactor()
  let changed = false
  for (const row of detailRows.value) {
    if (shouldSyncConsultFactor && !isSameNullableNumber(row.consultCategoryFactor, consultFactor)) {
      row.consultCategoryFactor = consultFactor
      changed = true
    }
    if (!shouldSyncMajorFactor) continue
    const majorDictId = resolveRowMajorDictId(row)
    if (!majorChangedRowIdSet.has(majorDictId)) continue
    const nextMajorFactor = getDefaultMajorFactorById(majorDictId)
    if (isSameNullableNumber(row.majorFactor, nextMajorFactor)) continue
    row.majorFactor = nextMajorFactor
    changed = true
  }
  if (!changed) return
  syncComputedValuesToDetailRows()
  await saveToIndexedDB({ skipComputedSync: true })*/
}

const syncLinkedScaleValuesFromContract = async (changedRowIds?: string[]) => {
  /*if (detailRows.value.length === 0) return
  const htData = await kvStore.getItem<{ detailRows: SourceRow[]; totalAmount?: number | null }>(HT_DB_KEY.value)
  const sourceRows = Array.isArray(htData?.detailRows) ? htData.detailRows : []
  const sourceRowMap = buildContractScaleMap(sourceRows)
  const sourceRowIdMap = buildContractScaleIdMap(sourceRows)
  const projectTotals = buildContractScaleProjectTotals(sourceRows, htData?.totalAmount)
  const useSummaryAmount = detailRows.value.length === 1 || isOnlyCostScaleService.value
  const onlyCostScaleFallbackAmount = isOnlyCostScaleService.value
    ? calcOnlyCostScaleAmountFromRows(sourceRows as Array<{ amount?: unknown; isGroupRow?: unknown }>, htData?.totalAmount)
    : null
  const changedRowIdSet = changedRowIds?.length ? normalizeChangedScaleRowIds(changedRowIds) : null

  let changed = false
  for (const row of detailRows.value) {
    if (changedRowIdSet && !useSummaryAmount) {
      const rowMajorId = resolveRowMajorDictId(row)
      if (!changedRowIdSet.has(rowMajorId)) continue
    }
    const sourceRow = getContractScaleRowByMajor(row, sourceRowMap, sourceRowIdMap)
    const nextAmount = row.hasCost
      ? (useSummaryAmount
          ? getContractScaleProjectTotalsByRow(row, projectTotals).amount
          : (typeof sourceRow?.amount === 'number' ? sourceRow.amount : onlyCostScaleFallbackAmount))
      : null
    if (isSameNullableNumber(row.amount, nextAmount)) continue
    row.amount = nextAmount
    changed = true
  }
  if (!changed) return
  syncComputedValuesToDetailRows()
  await saveToIndexedDB({ skipComputedSync: true })*/
}

const getRowId = (params: { data?: DetailRow }) => String(params.data?.id || '')
const detailGridOptions: GridOptions<DetailRow> = {
  ...gridOptions,
  getRowId,
  groupDefaultExpanded: -1,  // 默认全部展开所有分组
  groupHideOpenParents: true  // 隐藏已展开的父行（分组标题行）
}

const linkedSourceSignature = computed(() => JSON.stringify({
  consultFactorChange:
    zxFwPricingStore.keyedStates[HT_CONSULT_FACTOR_CHANGE_KEY.value]
    ?? kvStore.entries[HT_CONSULT_FACTOR_CHANGE_KEY.value]
    ?? null,
  majorFactorChange:
    zxFwPricingStore.keyedStates[HT_MAJOR_FACTOR_CHANGE_KEY.value]
    ?? kvStore.entries[HT_MAJOR_FACTOR_CHANGE_KEY.value]
    ?? null
}))

const linkedContractScaleSignature = computed(() => JSON.stringify(
  kvStore.entries[HT_SCALE_CHANGE_KEY.value] ?? null
))

const buildRowsFromImportDefaultSource = async (
  targetProjectCount: number
): Promise<DetailRow[]> => {
  // 与“使用默认数据”同源：先强制刷新系数，再按合同卡片默认带出。
  /*await loadFactorDefaults()
  const htData = await kvStore.getItem<{ detailRows: SourceRow[]; totalAmount?: number | null }>(HT_DB_KEY.value)
  const hasContractRows = Array.isArray(htData?.detailRows) && htData.detailRows.length > 0
  if (isOnlyCostScaleService.value) {
    return hasContractRows
      ? buildOnlyCostScaleRows(htData!.detailRows as any, {
          projectCount: targetProjectCount,
          cloneFromProjectOne: true,
          totalAmount: htData?.totalAmount ?? null,
          preferSummaryAmountWhenSingleRow: true
        })
      : buildOnlyCostScaleRows(undefined, {
          projectCount: targetProjectCount,
          totalAmount: htData?.totalAmount ?? null,
          preferSummaryAmountWhenSingleRow: true
        })
  }
  return hasContractRows
    ? mergeWithDictRows(htData!.detailRows, {
        includeFactorValues: true,
        projectCount: targetProjectCount,
        cloneFromProjectOne: true
      })
    : buildDefaultRows(targetProjectCount).map(row => ({
        ...row,
        consultCategoryFactor: getDefaultConsultCategoryFactor(),
        majorFactor: getDefaultMajorFactorById(row.majorDictId || row.id)
      }))*/
}

const readBaseIndustryCode = async () => {
  const baseInfo = await kvStore.getItem<XmBaseInfoState>(BASE_INFO_KEY.value)
  return typeof baseInfo?.projectIndustry === 'string' ? baseInfo.projectIndustry.trim() : ''
}

const buildRowsFromStoredState = (rows: DetailRow[]) =>
  isOnlyCostScaleService.value
    ? buildOnlyCostScaleRows(rows as any, {
        projectCount: getTargetProjectCount(),
        cloneFromProjectOne: true
      })
    : mergeWithDictRows(rows as any, {
        projectCount: getTargetProjectCount(),
        cloneFromProjectOne: true
      })

const buildEmptyRows = (targetProjectCount: number) =>
  isOnlyCostScaleService.value
    ? buildOnlyCostScaleRows(undefined, { projectCount: targetProjectCount })
    : buildDefaultRows(targetProjectCount)

const applyDetailRows = (rows: DetailRow[]) => {
  detailRows.value = rows.map(row => ({
    ...row,
    benchmarkBudgetBasicChecked:
      typeof row.benchmarkBudgetBasicChecked === 'boolean' ? row.benchmarkBudgetBasicChecked : true,
    benchmarkBudgetOptionalChecked:
      typeof row.benchmarkBudgetOptionalChecked === 'boolean' ? row.benchmarkBudgetOptionalChecked : true
  }))
}

const relabelDetailRowsFromDict = async () => {
  rebuildScaleDictCaches()
  if (detailRows.value.length === 0) {
    gridApi.value?.refreshCells({ force: true })
    return
  }
  const majorMetaMap = new Map<string, Pick<DetailRow, 'groupCode' | 'groupName' | 'majorCode' | 'majorName'>>()
  for (const group of detailDict) {
    majorMetaMap.set(group.id, {
      groupCode: group.code,
      groupName: group.name,
      majorCode: group.code,
      majorName: group.name
    })
    for (const child of group.children) {
      majorMetaMap.set(child.id, {
        groupCode: group.code,
        groupName: group.name,
        majorCode: child.code,
        majorName: child.name
      })
    }
  }
  let changed = false
  detailRows.value = detailRows.value.map(row => {
    const meta = majorMetaMap.get(resolveRowMajorDictId(row))
    if (!meta) return row
    if (
      row.groupCode === meta.groupCode &&
      row.groupName === meta.groupName &&
      row.majorCode === meta.majorCode &&
      row.majorName === meta.majorName
    ) {
      return row
    }
    changed = true
    return {
      ...row,
      groupCode: meta.groupCode,
      groupName: meta.groupName,
      majorCode: meta.majorCode,
      majorName: meta.majorName
    }
  })
  gridApi.value?.refreshCells({ force: true })
  if (!changed) return
  syncComputedValuesToDetailRows()
  await saveToIndexedDB({ skipComputedSync: true })
}

const mergeProjectExpandedRow = (defaultRow: DetailRow, existingRow: DetailRow): DetailRow => ({
  ...defaultRow,
  ...existingRow,
  id: defaultRow.id,
  projectIndex: defaultRow.projectIndex,
  majorDictId: defaultRow.majorDictId,
  groupCode: defaultRow.groupCode,
  groupName: defaultRow.groupName,
  majorCode: defaultRow.majorCode,
  majorName: defaultRow.majorName,
  hasCost: defaultRow.hasCost,
  hasArea: defaultRow.hasArea,
  path: defaultRow.path
})

const persistProjectCountChange = async () => {
  syncComputedValuesToDetailRows()
  await saveToIndexedDB({ skipComputedSync: true })
}

const applyProjectCountChange = async (nextValue: unknown) => {
  await applyPricingScaleProjectCountChange({
    nextValue,
    setProjectCount: count => {
      projectCount.value = count
    },
    isMutipleService: isMutipleService.value,
    currentRows: detailRows.value,
    cloneRows: rows => rows.map(row => ({ ...row })),
    normalizeProjectCount,
    inferProjectCountFromRows: rows => inferProjectCountFromRows(rows),
    buildRowsForReducedCount: (rows, targetProjectCount) =>
      isOnlyCostScaleService.value
        ? buildOnlyCostScaleRows(rows as any, { projectCount: targetProjectCount })
        : mergeWithDictRows(rows as any, { projectCount: targetProjectCount }),
    buildRowsFromImportDefaultSource,
    getRowKey: row => getScaleProjectMajorKeyFromRow(row),
    getRowProjectIndex: row => resolveRowProjectIndex(row),
    mergeExistingRow: mergeProjectExpandedRow,
    applyRows: applyDetailRows,
    afterApplyRows: persistProjectCountChange
  })
}

const loadFromIndexedDB = async () => {
  await loadC0Amount()
  try {
    const investmentRows = await useDataStore().query([
      { field: 'type', value: `${props.contractId}-investment`, operator: 'eq' }
    ])

    const detailRowsFromStore: DetailRow[] = investmentRows.map(row => ({
      id: String(row.id || ''),
      projectIndex: row.projectIndex != null ? Number(row.projectIndex) : undefined,
      majorDictId: row.majorDictId != null ? String(row.majorDictId) : undefined,
      groupCode: String(row.groupCode || ''),
      groupName: String(row.groupName || ''),
      majorCode: String(row.majorCode || ''),
      majorName: String(row.majorName || ''),
      hasCost: Boolean(row.hasCost),
      hasArea: Boolean(row.hasArea),
      amount: row.amount != null ? Number(row.amount) : null,
      benchmarkBudget: row.benchmarkBudget != null ? Number(row.benchmarkBudget) : null,
      benchmarkBudgetBasic: row.benchmarkBudgetBasic != null ? Number(row.benchmarkBudgetBasic) : null,
      benchmarkBudgetOptional: row.benchmarkBudgetOptional != null ? Number(row.benchmarkBudgetOptional) : null,
      benchmarkBudgetBasicChecked: Boolean(row.benchmarkBudgetBasicChecked),
      benchmarkBudgetOptionalChecked: Boolean(row.benchmarkBudgetOptionalChecked),
      basicFormula: row.basicFormula != null ? String(row.basicFormula) : null,
      optionalFormula: row.optionalFormula != null ? String(row.optionalFormula) : null,
      consultCategoryFactor: row.consultCategoryFactor != null ? Number(row.consultCategoryFactor) : null,
      majorFactor: row.majorFactor != null ? Number(row.majorFactor) : null,
      workStageFactor: row.workStageFactor,
      workRatio: row.workRatio,
      budgetFee: row.budgetFee != null ? Number(row.budgetFee) : null,
      budgetFeeBasic: row.budgetFeeBasic != null ? Number(row.budgetFeeBasic) : null,
      budgetFeeOptional: row.budgetFeeOptional != null ? Number(row.budgetFeeOptional) : null,
      serviceFee: row.serviceFee != null ? Number(row.budgetFee * row.workRatio * row.workStageFactor) : 0,
      remark: String(row.remark || ''),
      path: Array.isArray(row.path) ? row.path : [],
      base: String(row.base || '')
    }))
    fallbackDetailRows.value = await mergeWithDictRows(detailRowsFromStore)
    console.log('✅ 转换后的 DetailRow 数据:', detailRowsFromStore)
  }  catch (error) {
    console.error('loadFromIndexedDB error:', error)
    // ✅ 出错时生成默认行
    fallbackDetailRows.value = await buildDefaultRows()
  }
  /*await loadPricingScalePaneRows({
    industry: {
      readIndustryCode: readBaseIndustryCode,
      setIndustryCode: code => {
        activeIndustryCode.value = code
      }
    },
    setProjectCount: count => {
      projectCount.value = count
    },
    ensureFactorDefaultsLoaded,
    shouldForceDefaultLoad,
    buildContractDefaultRows: buildRowsFromImportDefaultSource,
    loadStoredState: () =>
      zxFwPricingStore.loadServicePricingMethodState<DetailRow>(props.contractId, props.serviceId, 'investScale'),
    isMutipleService: isMutipleService.value,
    normalizeProjectCount,
    inferProjectCountFromRows: rows => inferProjectCountFromRows(rows as any),
    buildRowsFromStoredState,
    buildEmptyRows,
    getTargetProjectCount,
    applyRows: applyDetailRows,
    afterApplyRows: syncComputedValuesToDetailRows,
    onError: error => {
      console.error('loadFromIndexedDB failed:', error)
    }
  })
  // ✅ 简单方案：直接调用 syncComputedValuesToDetailRows 并刷新表格
  if (gridApi.value && detailRows.value.length > 0) {
    syncComputedValuesToDetailRows()
    await nextTick()
    gridApi.value.refreshCells({ force: true })
    gridApi.value.redrawRows()
  }*/
}

const importContractData = async () => {
  await importPricingScalePaneRows({
    industry: {
      readIndustryCode: readBaseIndustryCode,
      setIndustryCode: code => {
        activeIndustryCode.value = code
      }
    },
    getTargetProjectCount,
    buildContractDefaultRows: buildRowsFromImportDefaultSource,
    applyRows: applyDetailRows,
    saveRows: () => saveToIndexedDB(),
    onError: error => {
      console.error('importContractData failed:', error)
    }
  })
}

const clearAllData = async () => {
  await clearPricingScalePaneRows({
    getTargetProjectCount,
    buildEmptyRows,
    applyRows: applyDetailRows,
    saveRows: () => saveToIndexedDB(),
    onError: error => {
      console.error('clearAllData failed:', error)
    }
  })
}

let isBulkClipboardMutation = false

const commitGridChanges = async (source: string) => {
  await nextTick()
  syncComputedValuesToDetailRows()
  gridApi.value?.refreshHeader()
  gridApi.value?.refreshCells({ force: true })
  await saveToIndexedDB({ skipComputedSync: true })
  await nextTick()
  gridApi.value?.refreshHeader()
  gridApi.value?.refreshCells({ force: true })
}

const handleCellValueChanged = (event?: any) => {
  recalculateServiceFees();
  saveToIndexedDB();
  // if (isBulkClipboardMutation) return
  // void commitGridChanges('cell-value-changed')
}

/*const handleBulkMutationStart = () => {
  isBulkClipboardMutation = true
}

const handleBulkMutationEnd = (event?: any) => {
  isBulkClipboardMutation = false
  void commitGridChanges(event?.type || 'bulk-end')
}

const handleGridReady = (event: GridReadyEvent<DetailRow>) => {
  gridApi.value = event.api
}*/

usePricingPaneLifecycle({
  gridApi,
  loadFromIndexedDB,
  syncLinkedFields: syncLinkedFieldsFromContractAndFactors,
  linkedSourceSignature,
  linkedSecondarySignature: linkedContractScaleSignature,
  syncSecondaryLinkedFields: () => {
    const state = (kvStore.entries[HT_SCALE_CHANGE_KEY.value] as ContractScaleChangeState | undefined) ?? undefined
    return syncLinkedScaleValuesFromContract(state?.changedRowIds)
  },
  saveToIndexedDB: () => saveToIndexedDB()
})
watch(
  () => locale.value,
  () => {
    void relabelDetailRowsFromDict()
  }
)
watch(
    () => useDataStore().items,
    async (newItems) => {
      if (Object.keys(newItems).length > 0) {
        loadFromIndexedDB();
      }
    },
    { immediate: true, deep: true }
)
const processCellForClipboard = (params: any) => {
  if (Array.isArray(params.value)) {
    return JSON.stringify(params.value); // 数组转字符串复制
  }
  return params.value;
};

const processCellFromClipboard = (params: any) => {
  const field = String(params.column?.getColDef?.().field || '')
  if (field === 'amount' || field === 'consultCategoryFactor' || field === 'majorFactor' || field === 'workStageFactor') {
    return parseNumberOrNull(params.value, { precision: 3 })
  }
  if (field === 'workRatio') {
    return parseNumberOrNull(params.value, { precision: 2 })
  }
  try {
    const parsed = JSON.parse(params.value);
    if (Array.isArray(parsed)) return parsed;
  } catch (e) {
    // 解析失败时返回原始值，无需额外处理
  }
  return params.value;
};


</script>

<template>
  <div class="h-full min-h-0 flex flex-col">


    <div class="rounded-lg border bg-card xmMx flex min-h-0 flex-1 flex-col">
      <div class="flex items-center justify-between border-b px-4 py-3">
        <div class="flex items-center gap-3">
          <h3 class="text-sm font-semibold text-foreground">{{ t('pricingPane.investment.title') }}</h3>
          <div v-if="isMutipleService" class="flex items-center gap-2">
            <span class="text-xs text-muted-foreground">{{ t('pricingPane.projectCount') }}</span>
            <NumberFieldRoot
              v-model="projectCount"
              :min="1"
              :step="1"
              class="inline-flex items-center rounded-md border bg-background"
              @update:model-value="value => void applyProjectCountChange(value)"
            >
              <NumberFieldDecrement class="cursor-pointer px-2 py-1 text-xs text-muted-foreground hover:bg-muted">-</NumberFieldDecrement>
              <NumberFieldInput class="h-7 w-14 border-x bg-transparent px-2 text-center text-xs outline-none" />
              <NumberFieldIncrement class="cursor-pointer px-2 py-1 text-xs text-muted-foreground hover:bg-muted">+</NumberFieldIncrement>
            </NumberFieldRoot>
          </div>
        </div>
<!--        <div class="flex items-center gap-2">-->
<!--          <AlertDialogRoot>-->
<!--            <AlertDialogTrigger as-child>-->
<!--              <Button type="button" variant="outline" size="sm">{{ t('common.clear') }}</Button>-->
<!--            </AlertDialogTrigger>-->
<!--            <AlertDialogPortal>-->
<!--              <AlertDialogOverlay class="fixed inset-0 z-50 bg-black/45" />-->
<!--              <AlertDialogContent class="fixed left-1/2 top-1/2 z-50 w-[92vw] max-w-md -translate-x-1/2 -translate-y-1/2 rounded-lg border bg-background p-5 shadow-xl">-->
<!--                <AlertDialogTitle class="text-base font-semibold">{{ t('pricingPane.clearTitle') }}</AlertDialogTitle>-->
<!--                <AlertDialogDescription class="mt-2 text-sm text-muted-foreground">-->
<!--                  {{ t('pricingPane.investment.clearDesc') }}-->
<!--                </AlertDialogDescription>-->
<!--                <div class="mt-4 flex items-center justify-end gap-2">-->
<!--                  <AlertDialogCancel as-child>-->
<!--                    <Button variant="outline">{{ t('common.cancel') }}</Button>-->
<!--                  </AlertDialogCancel>-->
<!--                  <AlertDialogAction as-child>-->
<!--                    <Button variant="destructive" @click="clearAllData">{{ t('pricingPane.confirmClear') }}</Button>-->
<!--                  </AlertDialogAction>-->
<!--                </div>-->
<!--              </AlertDialogContent>-->
<!--            </AlertDialogPortal>-->
<!--          </AlertDialogRoot>-->
<!--          <AlertDialogRoot>-->
<!--            <AlertDialogTrigger as-child>-->
<!--              <Button type="button" variant="outline" size="sm">{{ t('pricingPane.useDefault') }}</Button>-->
<!--            </AlertDialogTrigger>-->
<!--            <AlertDialogPortal>-->
<!--              <AlertDialogOverlay class="fixed inset-0 z-50 bg-black/45" />-->
<!--              <AlertDialogContent class="fixed left-1/2 top-1/2 z-50 w-[92vw] max-w-md -translate-x-1/2 -translate-y-1/2 rounded-lg border bg-background p-5 shadow-xl">-->
<!--                <AlertDialogTitle class="text-base font-semibold">{{ t('pricingPane.overrideTitle') }}</AlertDialogTitle>-->
<!--                <AlertDialogDescription class="mt-2 text-sm text-muted-foreground">-->
<!--                  {{ t('pricingPane.investment.overrideDesc') }}-->
<!--                </AlertDialogDescription>-->
<!--                <div class="mt-4 flex items-center justify-end gap-2">-->
<!--                  <AlertDialogCancel as-child>-->
<!--                    <Button variant="outline">{{ t('common.cancel') }}</Button>-->
<!--                  </AlertDialogCancel>-->
<!--                  <AlertDialogAction as-child>-->
<!--                    <Button @click="importContractData">{{ t('pricingPane.confirmOverride') }}</Button>-->
<!--                  </AlertDialogAction>-->
<!--                </div>-->
<!--              </AlertDialogContent>-->
<!--            </AlertDialogPortal>-->
<!--          </AlertDialogRoot>-->
<!--        </div>-->
      </div>

      <div :class="agGridWrapClass">
        <AgGridVue :style="agGridStyle" :rowData="detailRows" :pinnedBottomRowData="pinnedTopRowData"
          :columnDefs="gridColumnDefs" :autoGroupColumnDef="autoGroupColumnDef" :gridOptions="detailGridOptions" :theme="myTheme"
          :animateRows="true"
          @grid-ready="handleGridReady"
          @cell-value-changed="handleCellValueChanged" :suppressColumnVirtualisation="true"
          @paste-start="handleBulkMutationStart" @paste-end="handleBulkMutationEnd"
          @fill-start="handleBulkMutationStart" @fill-end="handleBulkMutationEnd"
          :suppressRowVirtualisation="true" :cellSelection="{ handle: { mode: 'range' } }" :enableClipboard="true"
          :localeText="AG_GRID_LOCALE_CN" :tooltipShowDelay="500" :headerHeight="50"
          :processCellForClipboard="processCellForClipboard" :processCellFromClipboard="processCellFromClipboard"
          :undoRedoCellEditing="true" :undoRedoCellEditingLimit="20" />
      </div>
    </div>
  </div>
</template>

