import type {
  CellPosition,
  ColDef,
  GridApi,
  GridSizeChangedEvent,
  FirstDataRenderedEvent,
  RowDataUpdatedEvent,
  ColumnResizedEvent,
  GridOptions,
  SuppressKeyboardEventParams
} from 'ag-grid-community'
import { themeQuartz } from 'ag-grid-community'

const borderConfig = {
  style: 'solid',
  width: 0.3,
  color: 'var(--border)'
}

export const myTheme = themeQuartz.withParams({
  wrapperBorder: false,
  wrapperBorderRadius: 0,
  headerBackgroundColor: 'var(--muted)',
  headerTextColor: 'var(--foreground)',
  headerFontSize: 15,
  headerFontWeight: 'normal',
  rowBorder: borderConfig,
  columnBorder: borderConfig,
  headerRowBorder: borderConfig,
  dataBackgroundColor: 'var(--card)'
})

// AG Grid 容器通用 class（占满父容器，配合父元素为 flex/grid 且有明确高度使用）
export const agGridWrapClass = 'ag-theme-quartz h-full min-h-0 w-full flex-1'

// AG Grid 组件通用 style（撑满容器 div）
export const agGridStyle = { height: '100%' }

const numericFieldKeywords = [
  'amount',
  'area',
  'cost',
  'price',
  'fee',
  'budget',
  'subtotal',
  'total',
  'ratio',
  'rate',
  'quantity',
  'count',
  'num',
  'workday',
  'workload',
  'hourly',
  'investscale',
  'landscale',
  'scale',
  'finalfee',
  'value',
  'coe',
  'factor'
]

const isLikelyNumericColumn = (params: any) => {
  const value = params?.value
  if (typeof value === 'number' && Number.isFinite(value)) return true

  const field = String(params?.colDef?.field || params?.column?.getColId?.() || '').toLowerCase()
  if (!field) return false
  return numericFieldKeywords.some(keyword => field.includes(keyword))
}

const isPlainEnterKey = (event: KeyboardEvent) =>
  event.key === 'Enter' && !event.altKey && !event.ctrlKey && !event.metaKey

const findNextEditableCellInColumn = (
  params: SuppressKeyboardEventParams,
  startRowIndex: number
): CellPosition | null => {
  const column = params.column
  for (let rowIndex = startRowIndex + 1; rowIndex < params.api.getDisplayedRowCount(); rowIndex += 1) {
    const rowNode = params.api.getDisplayedRowAtIndex(rowIndex)
    if (!rowNode || rowNode.group || rowNode.rowPinned) continue
    if (!column.isCellEditable(rowNode)) continue
    return {
      rowIndex,
      rowPinned: rowNode.rowPinned ?? null,
      column
    }
  }
  return null
}

const focusCellPosition = (
  params: SuppressKeyboardEventParams,
  cellPosition: CellPosition | null
) => {
  const target = cellPosition || {
    rowIndex: params.node.rowIndex ?? 0,
    rowPinned: params.node.rowPinned ?? null,
    column: params.column
  }
  window.setTimeout(() => {
    if (params.api.isDestroyed?.()) return
    params.api.ensureIndexVisible(target.rowIndex)
    params.api.setFocusedCell(target.rowIndex, target.column, target.rowPinned)
  }, 0)
}

const suppressExcelLikeEnter = (params: SuppressKeyboardEventParams) => {
  if (!isPlainEnterKey(params.event)) return false
  if (params.event.defaultPrevented || params.event.isComposing) return false

  params.event.preventDefault()
  params.event.stopPropagation()
  params.api.stopEditing()

  const currentRowIndex = params.node.rowIndex
  if (currentRowIndex == null) {
    focusCellPosition(params, null)
    return true
  }

  const nextCell = findNextEditableCellInColumn(params, currentRowIndex)
  focusCellPosition(params, nextCell)
  return true
}

const syncRowHeightsWithJs = (api: GridApi | null | undefined) => {
  if (!api || api.isDestroyed?.()) return
  // 统一使用 JS 重算，规避 wrapText/居中样式组合导致的高度滞后。
  setTimeout(() => {
    if (!api || api.isDestroyed?.()) return
    api.onRowHeightChanged()
    api.refreshCells({ force: true })
    api.redrawRows()
  }, 0)
}

export const agGridDefaultColDef: ColDef = {
  resizable: true,
  sortable: false,
  filter: false,
  wrapHeaderText: true,
  autoHeaderHeight: true,
  suppressKeyboardEvent: suppressExcelLikeEnter,
  // 默认把数值型单元格右对齐，减少每个列重复配置。
  cellClassRules: {
    'ag-right-aligned-cell': params => isLikelyNumericColumn(params)
  }
}

export const gridOptions: GridOptions = {
  treeData: true,
  animateRows: true,
  tooltipShowMode: 'whenTruncated',
  suppressAggFuncInHeader: true,
  singleClickEdit: true,
  stopEditingWhenCellsLoseFocus: true,
  suppressClickEdit: false,
  suppressContextMenu: false,
  groupDefaultExpanded: -1,
  suppressFieldDotNotation: true,
  enterNavigatesVertically: true,
  enterNavigatesVerticallyAfterEdit: true,
  // rowData 更新后通过稳定 ID 维持展开状态和编辑上下文。
  getRowId: params => {
    const id = params.data?.id
    if (id != null && String(id).trim()) return String(id)
    const path = Array.isArray(params.data?.path)
      ? params.data.path.map((segment: unknown) => String(segment ?? '').trim()).filter(Boolean)
      : []
    if (path.length > 0) return path.join('/')
    return '__row__'
  },
  // 兜底避免 AG Grid #185：treeData 模式下 path 不能为空数组。
  getDataPath: data => {
    const path = Array.isArray(data?.path)
      ? data.path.map((segment: unknown) => String(segment ?? '').trim()).filter(Boolean)
      : []
    if (path.length > 0) return path
    const fallback = String(data?.id ?? '').trim()
    return [fallback || '__row__']
  },
  getContextMenuItems: () => ['copy', 'paste', 'separator', 'export'],
  defaultColDef: agGridDefaultColDef,
  defaultColGroupDef: {
    wrapHeaderText: true,
    autoHeaderHeight: true
  },
  onFirstDataRendered: (event: FirstDataRenderedEvent) => {
    syncRowHeightsWithJs(event.api)
  },
  onRowDataUpdated: (event: RowDataUpdatedEvent) => {
    syncRowHeightsWithJs(event.api)
  },
  onGridSizeChanged: (event: GridSizeChangedEvent) => {
    syncRowHeightsWithJs(event.api)
  },
  onColumnResized: (event: ColumnResizedEvent) => {
    syncRowHeightsWithJs(event.api)
  }
}
