<script setup lang="ts">
import { computed, defineComponent, h, nextTick, onActivated, onBeforeUnmount, onMounted, ref, watch, type PropType } from 'vue'
import { useI18n } from 'vue-i18n'
import { AgGridVue } from 'ag-grid-vue3'
import type { CellValueChangedEvent, ColDef, GridApi, GridOptions, GridReadyEvent, ICellRendererParams } from 'ag-grid-community'
import { AG_GRID_LOCALE_CN } from '@ag-grid-community/locale'
import { myTheme, gridOptions, agGridWrapClass, agGridStyle } from '@/lib/diyAgGridOptions'
import { withReadonlyAutoHeight } from '@/lib/agGridReadonlyAutoHeight'
import { roundTo, sumNullableNumbers, toFiniteNumber, toFiniteNumberOrZero } from '@/lib/decimal'
import { parseNumberOrNull } from '@/lib/number'
import { formatThousandsFlexible } from '@/lib/numberFormat'
import { Pencil, Eraser } from 'lucide-vue-next'
import { Button } from '@/components/ui/button'
import { useTabStore } from '@/pinia/tab'
import { useZxFwPricingStore } from '@/pinia/zxFwPricing'
import {
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogOverlay,
  AlertDialogPortal,
  AlertDialogRoot,
  AlertDialogTitle
} from 'reka-ui'

interface FeeMethodRow {
  id: string
  name: string
  rateFee: number | null
  hourlyFee: number | null
  quantityUnitPriceFee: number | null
  subtotal?: number | null
  actions?: unknown
}

interface FeeMethodState {
  detailRows: FeeMethodRow[]
}

interface MethodRateState {
  rate?: unknown
  budgetFee?: unknown
}

interface MethodHourlyRowLike {
  adoptedBudgetUnitPrice?: unknown
  personnelCount?: unknown
  workdayCount?: unknown
  serviceBudget?: unknown
}

interface MethodHourlyState {
  detailRows?: MethodHourlyRowLike[]
}

interface MethodQuantityRowLike {
  id?: unknown
  budgetFee?: unknown
  quantity?: unknown
  unitPrice?: unknown
}

interface MethodQuantityState {
  detailRows?: MethodQuantityRowLike[]
}

interface LegacyFeeRow {
  id?: string
  feeItem?: string
  budgetFee?: number | null
  quantity?: number | null
  unitPrice?: number | null
}

const props = defineProps<{
  title: string
  storageKey: string
  contractId?: string
  contractName?: string
  fixedNames?: any[]
}>()
const { t } = useI18n()
const tabStore = useTabStore()
const zxFwPricingStore = useZxFwPricingStore()
const createRowId = () => `fee-method-${Date.now()}-${Math.random().toString(16).slice(2, 8)}`
const createDefaultRow = (name = ''): FeeMethodRow => ({
  id: createRowId(),
  name,
  rateFee: null,
  hourlyFee: null,
  quantityUnitPriceFee: null
})
const SUMMARY_ROW_ID = 'fee-method-summary'

const isSummaryRow = (row: FeeMethodRow | null | undefined) => row?.id === SUMMARY_ROW_ID
const isReserveStorageKey = (key: string) => String(key || '').includes('-reserve')
const sumNullableField = (rows: FeeMethodRow[], pick: (row: FeeMethodRow) => number | null | undefined): number | null => {
  const total = sumNullableNumbers(rows.map(row => pick(row)))
  return total == null ? null : roundTo(total, 3)
}
const getRowSubtotal = (row: FeeMethodRow | null | undefined) => {
  if (!row) return null
  const values = [row.rateFee, row.hourlyFee, row.quantityUnitPriceFee]
  const total = sumNullableNumbers(values)
  if (total == null) return null
  return roundTo(total, 3)
}

const sumMainStateSubtotal = (rows: FeeMethodRow[] | undefined) => {
  if (!Array.isArray(rows) || rows.length === 0) return null
  return sumNullableField(rows, row => getRowSubtotal(row))
}

const loadAdditionalWorkFeeTotal = async (contractId: string): Promise<number | null> => {
  try {
    const additionalStorageKey = `htExtraFee-${contractId}-additional-work`
    const additionalState = await zxFwPricingStore.loadHtFeeMainState<FeeMethodRow>(additionalStorageKey)
    return sumMainStateSubtotal(additionalState?.detailRows)
  } catch (error) {
    console.error('loadAdditionalWorkFeeTotal failed:', error)
    return null
  }
}

const loadContractServiceFeeBase = async (): Promise<number | null> => {
  const contractId = String(props.contractId || '').trim()
  if (!contractId) return null
  try {
    await zxFwPricingStore.loadContract(contractId)
    const serviceBase = zxFwPricingStore.getBaseSubtotal(contractId)
    if (!isReserveStorageKey(props.storageKey)) {
      return serviceBase == null ? null : roundTo(serviceBase, 3)
    }
    const additionalFeeTotal = await loadAdditionalWorkFeeTotal(contractId)
    const hasAnyBase = serviceBase != null || additionalFeeTotal != null
    if (!hasAnyBase) return null
    return roundTo(toFiniteNumberOrZero(serviceBase) + toFiniteNumberOrZero(additionalFeeTotal), 3)
  } catch (error) {
    console.error('loadContractServiceFeeBase failed:', error)
    return null
  }
}

const sumHourlyMethodFee = (state: MethodHourlyState | null): number | null => {
  
  
  const rows=state?.detailRows?state?.detailRows?.filter(e=>e.serviceBudget!== null):[]
  
  if (rows.length === 0) return null
  let total = 0
  let hasValid = false
  for (const row of rows) {
    
    const rowBudget = toFiniteNumber(row?.serviceBudget)
    if (rowBudget != null) {
      total += rowBudget
      hasValid = true
      continue
    }
    const adopted = toFiniteNumber(row?.adoptedBudgetUnitPrice)
    const personnel = toFiniteNumber(row?.personnelCount)
    const workday = toFiniteNumber(row?.workdayCount)
    
    if (adopted == null || personnel == null || workday == null) continue
    total += adopted * personnel * workday
    hasValid = true
  }
  return hasValid ? roundTo(total, 3) : null
}

const sumQuantityMethodFee = (state: MethodQuantityState | null): number | null => {
  const rows=state?.detailRows?state?.detailRows?.filter(e=>e.budgetFee!== null):[]
  if (rows.length === 0) return null

  let total = 0
  let hasValid = false
  for (const row of rows) {
    if (String(row?.id || '') === 'fee-subtotal-fixed') continue
    const budget = toFiniteNumber(row?.budgetFee)
    if (budget != null) {
      total += budget
      hasValid = true
      continue
    }
    const quantity = toFiniteNumber(row?.quantity)
    const unitPrice = toFiniteNumber(row?.unitPrice)
    if (quantity == null || unitPrice == null) continue
    total += quantity * unitPrice
    hasValid = true
  }
  return hasValid ? roundTo(total, 3) : null
}

const hydrateRowsFromMethodStores = async (rows: FeeMethodRow[]): Promise<FeeMethodRow[]> => {
  if (!Array.isArray(rows) || rows.length === 0) return rows
  const contractBase = await loadContractServiceFeeBase()
  const hydratedRows = await Promise.all(
    rows.map(async row => {
      if (!row?.id) return row
      const [rateData, hourlyData, quantityData] = await Promise.all([
        zxFwPricingStore.loadHtFeeMethodState<MethodRateState>(props.storageKey, row.id, 'rate-fee'),
        zxFwPricingStore.loadHtFeeMethodState<MethodHourlyState>(props.storageKey, row.id, 'hourly-fee'),
        zxFwPricingStore.loadHtFeeMethodState<MethodQuantityState>(props.storageKey, row.id, 'quantity-unit-price-fee')
      ])

      const storedRateFee = toFiniteNumber(rateData?.budgetFee)
      const rateValue = toFiniteNumber(rateData?.rate)
      const rateFee =
        contractBase != null && rateValue != null
          ? roundTo(contractBase * rateValue / 100, 2)
          : storedRateFee != null
            ? roundTo(storedRateFee, 2)
            : null

      const hourlyFee = sumHourlyMethodFee(hourlyData)
      const quantityUnitPriceFee = sumQuantityMethodFee(quantityData)

      return {
        ...row,
        rateFee,
        hourlyFee,
        quantityUnitPriceFee
      }
    })
  )
  return hydratedRows
}

const fixedNames = computed(() =>
  Array.isArray(props.fixedNames)
    ? props.fixedNames.map(item => ({name:item.name,id:item.id}))
    : []
)
const hasFixedNames = computed(() => fixedNames.value.length > 0)
const fixedNamesSignature = computed(() =>
  JSON.stringify(
    fixedNames.value.map(item => ({
      id: String(item?.id || ''),
      name: String(item?.name || '')
    }))
  )
)
const detailRows = computed<FeeMethodRow[]>({
  get: () => {
    const rows = zxFwPricingStore.getHtFeeMainState<FeeMethodRow>(props.storageKey)?.detailRows
    return Array.isArray(rows) ? rows : []
  },
  set: rows => {
    zxFwPricingStore.setHtFeeMainState(props.storageKey, {
      detailRows: rows
    })
  }
})
const summaryRow = computed<FeeMethodRow>(() => {
  const rateFee = sumNullableField(detailRows.value, row => row.rateFee)
  const hourlyFee = sumNullableField(detailRows.value, row => row.hourlyFee)
  const quantityUnitPriceFee = sumNullableField(detailRows.value, row => row.quantityUnitPriceFee)
  const result: FeeMethodRow = {
    id: SUMMARY_ROW_ID,
    name: t('htFeeGrid.subtotal'),
    rateFee,
    hourlyFee,
    quantityUnitPriceFee
  }
  result.subtotal = getRowSubtotal(result)
  return result
})
const displayRows = computed<FeeMethodRow[]>(() => [...detailRows.value, summaryRow.value])
const gridApi = ref<GridApi<FeeMethodRow> | null>(null)
const clearConfirmOpen = ref(false)
const pendingClearRowId = ref<string | null>(null)
const pendingClearRowName = ref('')
const lastSavedSnapshot = ref('')

const requestClearRow = (id: string, name?: string) => {
  pendingClearRowId.value = id
  pendingClearRowName.value = String(name || '').trim() || t('htFeeGrid.currentRow')
  clearConfirmOpen.value = true
}

const handleClearConfirmOpenChange = (open: boolean) => {
  clearConfirmOpen.value = open
}

const confirmClearRow = async () => {
  const id = pendingClearRowId.value
  if (!id) return
  await clearRow(id)
  clearConfirmOpen.value = false
  pendingClearRowId.value = null
  pendingClearRowName.value = ''
}

const formatEditableText = (params: any) => {
  if (params.value == null || params.value === '') {
    if (isSummaryRow(params.data)) return ''
    return ''
  }
  return String(params.value)
}

const formatEditableNumber = (params: any) => {
  if (params.value == null || params.value === '') {
    if (isSummaryRow(params.data)) return ''
    return ''
  }
  return formatThousandsFlexible(params.value, 3)
}

const numericParser = (newValue: any): number | null =>
  parseNumberOrNull(newValue, { precision: 3 })

const toLegacyQuantityUnitPriceFee = (row: LegacyFeeRow) => {
  if (typeof row.budgetFee === 'number' && Number.isFinite(row.budgetFee)) return row.budgetFee
  if (
    typeof row.quantity === 'number' &&
    Number.isFinite(row.quantity) &&
    typeof row.unitPrice === 'number' &&
    Number.isFinite(row.unitPrice)
  ) {
    return roundTo(row.quantity * row.unitPrice, 2)
  }
  return null
}

const mergeWithStoredRows = (rowsFromDb: unknown): FeeMethodRow[] => {
  
  const sourceRows = (Array.isArray(rowsFromDb) ? rowsFromDb : []).filter(
    item => (item as Partial<FeeMethodRow>)?.id !== SUMMARY_ROW_ID
  )
  const rows = sourceRows.map(item => {
    const row = item as Partial<FeeMethodRow> & LegacyFeeRow
    return {
      id: typeof row.id === 'string' && row.id ? row.id : createRowId(),
      name:
        typeof row.name === 'string'
          ? row.name
          : (typeof row.feeItem === 'string' ? row.feeItem : ''),

      rateFee: typeof row.rateFee === 'number' ? row.rateFee : null,
      hourlyFee: typeof row.hourlyFee === 'number' ? row.hourlyFee : null,
      quantityUnitPriceFee:
        typeof row.quantityUnitPriceFee === 'number'
          ? row.quantityUnitPriceFee
          : toLegacyQuantityUnitPriceFee(row)
    } as FeeMethodRow
  })
  
  if (hasFixedNames.value) {
    const byId = new Map(rows.map(row => [String(row.id || ''), row]))
    const byName = new Map(rows.map(row => [row.name, row]))
    return fixedNames.value.map((item, index) => {
      const rowId = String(item?.id || `fee-method-fixed-${index}`)
      const fromDb = byId.get(rowId) || byName.get(item.name)
      return {
        id: rowId,
        name: item.name,
        rateFee: fromDb?.rateFee ?? null,
        hourlyFee: fromDb?.hourlyFee ?? null,
        quantityUnitPriceFee: fromDb?.quantityUnitPriceFee ?? null
      }
    })
  }
  return rows.length > 0 ? rows : [createDefaultRow()]
}

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

const saveToIndexedDB = async (force = false) => {
  try {
    const payload: FeeMethodState = {
      detailRows: JSON.parse(JSON.stringify(buildPersistDetailRows()))
    }
    const snapshot = JSON.stringify(payload.detailRows)
    if (!force && snapshot === lastSavedSnapshot.value) return
    zxFwPricingStore.setHtFeeMainState(props.storageKey, payload, { force })
    lastSavedSnapshot.value = snapshot
  } catch (error) {
    console.error('saveToIndexedDB failed:', error)
  }
}

const loadFromIndexedDB = async () => {
  try {
    const data = await zxFwPricingStore.loadHtFeeMainState<FeeMethodRow>(props.storageKey)
    const mergedRows = mergeWithStoredRows(data?.detailRows)
    detailRows.value = await hydrateRowsFromMethodStores(mergedRows)
    await saveToIndexedDB(true)
  } catch (error) {
    console.error('loadFromIndexedDB failed:', error)
    const mergedRows = mergeWithStoredRows([])
    detailRows.value = await hydrateRowsFromMethodStores(mergedRows)
    await saveToIndexedDB(true)
  }
}

const addRow = () => {
  detailRows.value = [...detailRows.value, createDefaultRow()]
  void saveToIndexedDB()
}

const clearRow = async (id: string) => {
  tabStore.removeTab(`ht-fee-edit-${props.storageKey}-${id}`)
  await nextTick()
  zxFwPricingStore.removeHtFeeMethodState(props.storageKey, id, 'rate-fee')
  zxFwPricingStore.removeHtFeeMethodState(props.storageKey, id, 'hourly-fee')
  zxFwPricingStore.removeHtFeeMethodState(props.storageKey, id, 'quantity-unit-price-fee')
  detailRows.value = detailRows.value.map(row =>
    row.id !== id
      ? row
      : {
          ...row,
          rateFee: null,
          hourlyFee: null,
          quantityUnitPriceFee: null
        }
  )
  await saveToIndexedDB()
}

const editRow = (id: string) => {
  const row = detailRows.value.find(item => item.id === id)
  if (!row) return
  tabStore.openTab({
    id: `ht-fee-edit-${props.storageKey}-${id}`,
    title: t('htFeeGrid.editTabTitle', { name: row.name || t('htFeeGrid.unnamed') }),
    componentName: 'HtFeeMethodTypeLineView',
    props: {
      sourceTitle: props.title,
      storageKey: props.storageKey,
      rowId: id,
      rowName: row.name || '',
      contractId: props.contractId,
      contractName: props.contractName
    }
  })
}

const ActionCellRenderer = defineComponent({
  name: 'HtFeeMethodActionCellRenderer',
  props: {
    params: {
      type: Object as PropType<ICellRendererParams<FeeMethodRow>>,
      required: true
    }
  },
  setup(props) {
      return () => {
        if (isSummaryRow(props.params.data as FeeMethodRow | undefined)) return null
        const onActionClick = (action: 'edit' | 'clear') => (event: MouseEvent) => {
          event.preventDefault()
          event.stopPropagation()
          const rowId = String(props.params.data?.id || '').trim()
          if (!rowId) return
          if (action === 'edit') {
            props.params.context?.onActionEdit?.(rowId)
            return
        }
        void props.params.context?.onActionRequestClear?.(rowId, String(props.params.data?.name || ''))
      }
      return h('div', { class: 'zxfw-action-wrap' }, [
        h('div', { class: 'zxfw-action-group' }, [
          h('button', {
            class: 'zxfw-action-btn',
            'data-action': 'edit',
            type: 'button',
            onClick: onActionClick('edit')
          }, [
            h(Pencil, { size: 13, 'aria-hidden': 'true' }),
            h('span', t('htFeeGrid.edit'))
          ]),
          h('button', {
            class: 'zxfw-action-btn zxfw-action-btn--danger',
            'data-action': 'clear',
            type: 'button',
            onClick: onActionClick('clear')
          }, [
            h(Eraser, { size: 13, 'aria-hidden': 'true' }),
            h('span', t('htFeeGrid.clear'))
          ])
        ])
      ])
    }
  }
})

const columnDefs: ColDef<FeeMethodRow>[] = [
  {
    headerName: t('htFeeGrid.columns.name'),
    field: 'name',
    minWidth: 180,
    flex: 1.8,
    editable: false,
    valueFormatter: formatEditableText,
    cellClass: params =>
      params.context?.fixedNames === true || isSummaryRow(params.data)
        ? ''
        : 'editable-cell-line',
    cellClassRules: {
      'ag-summary-label-cell': params => isSummaryRow(params.data),
      'editable-cell-empty': params => params.value == null || params.value === ''
    }
  },
  {
    headerName: t('htFeeGrid.columns.rateFee'),
    field: 'rateFee',
    minWidth: 130,
    flex: 1.2,
    editable: false,
    headerClass: 'ag-right-aligned-header',
    valueParser: params => numericParser(params.newValue),
    valueFormatter: formatEditableNumber,
    cellClassRules: {
      'ag-right-aligned-cell': () => true,
      'editable-cell-empty': params => params.value == null || params.value === ''
    }
  },
  {
    headerName: t('htFeeGrid.columns.hourlyFee'),
    field: 'hourlyFee',
    minWidth: 130,
    flex: 1.2,
    editable: false,
    headerClass: 'ag-right-aligned-header',
    valueParser: params => numericParser(params.newValue),
    valueFormatter: formatEditableNumber,
    cellClassRules: {
      'ag-right-aligned-cell': () => true,
      'editable-cell-empty': params => params.value == null || params.value === ''
    }
  },
  {
    headerName: t('htFeeGrid.columns.quantityUnitPriceFee'),
    field: 'quantityUnitPriceFee',
    minWidth: 130,
    flex: 1.2,
    editable: false,
    headerClass: 'ag-right-aligned-header',
    valueParser: params => numericParser(params.newValue),
    valueFormatter: formatEditableNumber,
    cellClassRules: {
      'ag-right-aligned-cell': () => true,
      'editable-cell-empty': params => params.value == null || params.value === ''
    }
  },
  {
    headerName: t('htFeeGrid.columns.subtotal'),
    field: 'subtotal',
    minWidth: 140,
    flex: 1.2,
    editable: false,
    headerClass: 'ag-right-aligned-header',
    cellClassRules: {
      'ag-right-aligned-cell': () => true
    },
    valueGetter: params => getRowSubtotal(params.data),
    valueFormatter: formatEditableNumber
  },
  {
    headerName: t('htFeeGrid.columns.actions'),
    field: 'actions',
    minWidth: 220,
    flex: 1.6,
    maxWidth: 260,
    editable: false,
    sortable: false,
    filter: false,
    suppressMovable: true,
    cellRenderer: ActionCellRenderer
  }
]
const gridColumnDefs = computed(() => withReadonlyAutoHeight(columnDefs))

const detailGridOptions: GridOptions<FeeMethodRow> = {
  ...gridOptions,
  treeData: false,
  getDataPath: undefined,
  context: {
    fixedNames: hasFixedNames.value,
    onActionEdit: editRow,
    onActionClear: clearRow,
    onActionRequestClear: requestClearRow
  },
  onCellClicked: params => {
    if (params.colDef.field !== 'actions' || !params.data || isSummaryRow(params.data)) return
    const target = params.event?.target as HTMLElement | null
    const btn = target?.closest('button[data-action]') as HTMLButtonElement | null
    const action = btn?.dataset.action
    if (action === 'edit') {
      editRow(params.data.id)
      return
    }
    if (action === 'clear') {
      requestClearRow(params.data.id, params.data.name)
      return
    }
  }
}

let reloadTimer: ReturnType<typeof setTimeout> | null = null

const scheduleReloadFromStorage = () => {
  if (reloadTimer) clearTimeout(reloadTimer)
  reloadTimer = setTimeout(() => {
    void loadFromIndexedDB()
  }, 80)
}

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

let isBulkClipboardMutation = false

const commitGridChanges = () => {
  void saveToIndexedDB()
}

const handleCellValueChanged = (event: CellValueChangedEvent<FeeMethodRow>) => {
  if (isBulkClipboardMutation) return
  if (isSummaryRow(event.data)) return
  commitGridChanges()
}

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

const handleBulkMutationEnd = () => {
  isBulkClipboardMutation = false
  commitGridChanges()
}

onMounted(async () => {
  await loadFromIndexedDB()
})

onActivated(() => {
  scheduleReloadFromStorage()
})

const storageKeyRef = computed(() => props.storageKey)
const reserveAdditionalWorkStateSignature = computed(() => {
  if (!isReserveStorageKey(props.storageKey)) return ''
  const contractId = String(props.contractId || '').trim()
  if (!contractId) return ''
  const additionalStorageKey = `htExtraFee-${contractId}-additional-work`
  return JSON.stringify(zxFwPricingStore.htFeeMainStates[additionalStorageKey] || null)
})
watch(storageKeyRef, () => {
  scheduleReloadFromStorage()
})

watch(
  () => JSON.stringify(zxFwPricingStore.htFeeMethodStates[props.storageKey] || null),
  (nextSignature, prevSignature) => {
    if (!nextSignature && !prevSignature) return
    if (nextSignature === prevSignature) return
    scheduleReloadFromStorage()
  }
)

watch(
  () => {
    const contractId = String(props.contractId || '').trim()
    if (!contractId) return ''
    return JSON.stringify(zxFwPricingStore.contracts[contractId] || null)
  },
  (nextSig, prevSig) => {
    if (nextSig === prevSig) return
    scheduleReloadFromStorage()
  }
)

watch(
  reserveAdditionalWorkStateSignature,
  (nextSig, prevSig) => {
    if (nextSig === prevSig) return
    scheduleReloadFromStorage()
  }
)

watch([hasFixedNames], () => {
  if (!detailGridOptions.context) return
  detailGridOptions.context.fixedNames = hasFixedNames.value
  detailGridOptions.context.onActionEdit = editRow
  detailGridOptions.context.onActionClear = clearRow
  detailGridOptions.context.onActionRequestClear = requestClearRow
  gridApi.value?.refreshCells({ force: true })
})

watch(
  fixedNamesSignature,
  async (nextSig, prevSig) => {
    if (!hasFixedNames.value) return
    if (!nextSig || nextSig === prevSig) return
    const nextRows = mergeWithStoredRows(detailRows.value)
    const changed = JSON.stringify(nextRows) !== JSON.stringify(detailRows.value)
    if (!changed) return
    detailRows.value = nextRows
    await saveToIndexedDB(true)
    gridApi.value?.refreshCells({ force: true })
  }
)

onBeforeUnmount(() => {
  if (reloadTimer) clearTimeout(reloadTimer)
  gridApi.value = null
  void saveToIndexedDB(true)
})
</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">
        <h3 class="text-sm font-semibold text-foreground">{{ title }}</h3>
        <Button v-if="!hasFixedNames" type="button" variant="outline" size="sm" @click="addRow">{{ t('htFeeGrid.add') }}</Button>
      </div>

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

  <AlertDialogRoot :open="clearConfirmOpen" @update:open="handleClearConfirmOpenChange">
    <AlertDialogPortal>
      <AlertDialogOverlay class="fixed inset-0 z-50 bg-black/45" />
      <AlertDialogContent class="fixed left-1/2 top-1/2 z-[70] 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('htFeeGrid.dialog.clearTitle') }}</AlertDialogTitle>
        <AlertDialogDescription class="mt-2 text-sm text-muted-foreground">
          {{ t('htFeeGrid.dialog.clearDesc', { name: pendingClearRowName }) }}
        </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="confirmClearRow">{{ t('htFeeGrid.dialog.confirmClear') }}</Button>
          </AlertDialogAction>
        </div>
      </AlertDialogContent>
    </AlertDialogPortal>
  </AlertDialogRoot>
</template>
