import type { ColDef, ColGroupDef } from 'ag-grid-community'

type AnyColDef<TRow> = ColDef<TRow> | ColGroupDef<TRow>

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

const isFiniteNumber = (value: unknown) => typeof value === 'number' && Number.isFinite(value)

const isNumericLikeString = (value: unknown) => {
  if (typeof value !== 'string') return false
  const normalized = value.replace(/[,\s]/g, '').replace(/%$/, '')
  if (!normalized) return false
  const asNumber = Number(normalized)
  return Number.isFinite(asNumber)
}

const looksNumericByColumnDef = <TRow>(col: ColDef<TRow>) => {
  const fieldLike = String(col.field ?? col.colId ?? '').toLowerCase()
  const hasNumericFieldHint = fieldLike
    ? numericFieldKeywords.some(keyword => fieldLike.includes(keyword))
    : false
  const type = col.type
  const typeList = Array.isArray(type) ? type : type ? [type] : []
  const hasNumericType = typeList.some(item => {
    const normalized = String(item).toLowerCase()
    return normalized.includes('numeric') || normalized.includes('rightaligned')
  })
  return hasNumericFieldHint || col.cellDataType === 'number' || hasNumericType
}

const hasRightAlignedHeaderClass = (value: unknown) => {
  if (typeof value === 'string') return value.includes('ag-right-aligned-header')
  if (Array.isArray(value)) return value.some(item => String(item).includes('ag-right-aligned-header'))
  return false
}

const mergeHeaderClass = <TRow>(col: ColDef<TRow>, mustRightAlign: boolean): ColDef<TRow>['headerClass'] => {
  if (!mustRightAlign) return col.headerClass

  const base = col.headerClass
  if (!base) return 'ag-right-aligned-header'
  if (hasRightAlignedHeaderClass(base)) return base

  if (typeof base === 'function') {
    return params => {
      const result = base(params)
      if (!result) return 'ag-right-aligned-header'
      if (typeof result === 'string') {
        return result.includes('ag-right-aligned-header')
          ? result
          : `${result} ag-right-aligned-header`
      }
      if (Array.isArray(result)) {
        return hasRightAlignedHeaderClass(result)
          ? result
          : [...result, 'ag-right-aligned-header']
      }
      return 'ag-right-aligned-header'
    }
  }

  if (typeof base === 'string') return `${base} ag-right-aligned-header`
  if (Array.isArray(base)) return [...base, 'ag-right-aligned-header']
  return base
}

const mergeNumericCellClassRules = <TRow>(
  col: ColDef<TRow>,
  mustRightAlign: boolean
): ColDef<TRow>['cellClassRules'] => {
  if (!mustRightAlign) return col.cellClassRules

  const baseRules = col.cellClassRules ? { ...col.cellClassRules } : {}
  const existing = baseRules['ag-right-aligned-cell']
  if (existing) return baseRules

  baseRules['ag-right-aligned-cell'] = params =>
    looksNumericByColumnDef(params.colDef as ColDef<TRow>) ||
    isFiniteNumber(params.value) ||
    isNumericLikeString(params.value)

  return baseRules
}

const mergeCellStyle = (cellStyle: ColDef['cellStyle']): ColDef['cellStyle'] => {
  const baseStyle = { whiteSpace: 'normal', lineHeight: '1.4' }
  if (!cellStyle) return baseStyle
  if (typeof cellStyle === 'function') {
    return params => {
      const next = cellStyle(params)
      if (next && typeof next === 'object') {
        return {
          ...next,
          ...baseStyle
        }
      }
      return baseStyle
    }
  }
  if (typeof cellStyle === 'object') {
    return {
      ...cellStyle,
      ...baseStyle
    }
  }
  return cellStyle
}

const enhanceLeafColumn = <TRow>(col: ColDef<TRow>): ColDef<TRow> => {
  const editable = col.editable
  const isReadonlyColumn = editable == null || editable === false
  const shouldRightAlign = looksNumericByColumnDef(col)
  if (!isReadonlyColumn) {
    return {
      ...col,
      headerClass: mergeHeaderClass(col, shouldRightAlign),
      cellClassRules: mergeNumericCellClassRules(col, shouldRightAlign)
    }
  }
  return {
    ...col,
    headerClass: mergeHeaderClass(col, shouldRightAlign),
    cellClassRules: mergeNumericCellClassRules(col, shouldRightAlign),
    wrapText: true,
    autoHeight: true,
    cellStyle: mergeCellStyle(col.cellStyle)
  }
}

const enhanceColumn = <TRow>(col: AnyColDef<TRow>): AnyColDef<TRow> => {
  const maybeGroup = col as ColGroupDef<TRow>
  if (Array.isArray(maybeGroup.children)) {
    return {
      ...maybeGroup,
      children: maybeGroup.children.map(child => enhanceColumn(child as AnyColDef<TRow>))
    }
  }
  return enhanceLeafColumn(col as ColDef<TRow>)
}

export const withReadonlyAutoHeight = <TRow>(
  defs: Array<AnyColDef<TRow>>
): Array<AnyColDef<TRow>> => defs.map(def => enhanceColumn(def))

