import type { ColDef, ColGroupDef } from 'ag-grid-community'
import {
  formatScaleEditableNumber,
  formatScaleReadonlyMoney,
  getScaleMergeColSpanBeforeTotal
} from '@/lib/pricingScaleGrid'
import { i18n } from '@/i18n'

type ScaleColumnField<TRow> = Extract<keyof TRow, string> | string
const scaleT = (key: string, params?: Record<string, unknown>) =>
  params ? i18n.global.t(`pricingScale.${key}`, params) : i18n.global.t(`pricingScale.${key}`)

export const createScaleValueColumn = <TRow>(options: {
  headerName: string
  field: ScaleColumnField<TRow>
  headerTooltip: string
  onReset: () => Promise<void> | void
  resetTitle: string
  headerComponent: any
  minWidth?: number
  flex?: number
  isEditable: (row: TRow | undefined) => boolean
  emptyTextPredicate: (row: TRow | undefined, value: unknown) => boolean
  valueParser: (params: any) => any
  valueFormatter: (params: any) => string
}) : ColDef<TRow> => ({
  headerName: options.headerName,
  field: options.field as any,
  headerTooltip: options.headerTooltip,
  headerComponent: options.headerComponent,
  headerComponentParams: {
    onReset: options.onReset,
    resetTitle: options.resetTitle
  },
  headerClass: 'ag-right-aligned-header',
  minWidth: options.minWidth ?? 90,
  flex: options.flex ?? 2,
  editable: params => !params.node?.group && !params.node?.rowPinned && options.isEditable(params.data),
  cellClass: params =>
    !params.node?.group && !params.node?.rowPinned && options.isEditable(params.data)
      ? 'editable-cell-line'
      : '',
  cellClassRules: {
    'ag-right-aligned-cell': () => true,
    'editable-cell-empty': params =>
      !params.node?.group && !params.node?.rowPinned && options.emptyTextPredicate(params.data, params.value)
  },
  valueParser: options.valueParser,
  valueFormatter: options.valueFormatter
})

export const createScaleBenchmarkBudgetColumnGroup = <TRow>(options: {
  getCheckedSplit: (row: TRow | undefined) => { basic?: number | null; optional?: number | null; total?: number | null } | null
  createBudgetCellRendererWithCheck: (field: 'benchmarkBudgetBasicChecked' | 'benchmarkBudgetOptionalChecked') => any
  getHeaderComponent?: (field: 'benchmarkBudgetBasicChecked' | 'benchmarkBudgetOptionalChecked') => any
  getHeaderComponentParams?: (field: 'benchmarkBudgetBasicChecked' | 'benchmarkBudgetOptionalChecked') => Record<string, unknown>
}) : ColGroupDef<TRow> => ({
  headerName: scaleT('columns.benchmarkBudget'),
  marryChildren: true,
  children: [
    {
      headerName: scaleT('columns.basicWork'),
      field: 'benchmarkBudgetBasic' as any,
      colId: 'benchmarkBudgetBasic',
      headerClass: 'ag-right-aligned-header',
      headerComponent: options.getHeaderComponent?.('benchmarkBudgetBasicChecked'),
      headerComponentParams: options.getHeaderComponentParams?.('benchmarkBudgetBasicChecked'),
      minWidth: 130,
      flex: 1,
      cellClassRules: {
        'ag-right-aligned-cell': () => true
      },
      valueGetter: params => (params.node?.rowPinned ? null : options.getCheckedSplit(params.data)?.basic ?? null),
      cellRenderer: options.createBudgetCellRendererWithCheck('benchmarkBudgetBasicChecked'),
      cellRendererParams: {
        suppressMouseEventHandling: () => true
      },
      valueFormatter: formatScaleReadonlyMoney
    },
    {
      headerName: scaleT('columns.optionalWork'),
      field: 'benchmarkBudgetOptional' as any,
      colId: 'benchmarkBudgetOptional',
      headerClass: 'ag-right-aligned-header',
      headerComponent: options.getHeaderComponent?.('benchmarkBudgetOptionalChecked'),
      headerComponentParams: options.getHeaderComponentParams?.('benchmarkBudgetOptionalChecked'),
      minWidth: 130,
      flex: 1,
      cellClassRules: {
        'ag-right-aligned-cell': () => true
      },
      valueGetter: params => (params.node?.rowPinned ? null : options.getCheckedSplit(params.data)?.optional ?? null),
      cellRenderer: options.createBudgetCellRendererWithCheck('benchmarkBudgetOptionalChecked'),
      cellRendererParams: {
        suppressMouseEventHandling: () => true
      },
      valueFormatter: formatScaleReadonlyMoney
    },
    {
      headerName: scaleT('columns.subtotal'),
      field: 'benchmarkBudget' as any,
      colId: 'benchmarkBudgetTotal',
      headerClass: 'ag-right-aligned-header',
      minWidth: 100,
      flex: 1,
      cellClassRules: {
        'ag-right-aligned-cell': () => true
      },
      valueGetter: params => (params.node?.rowPinned ? null : options.getCheckedSplit(params.data)?.total ?? null),
      valueFormatter: formatScaleReadonlyMoney
    }
  ]
})

export const createScaleBudgetFeeColumnGroup = <TRow>(options: {
  headerComponent: any
  restoreConsultCategoryFactorColumnDefaults: () => Promise<void> | void
  restoreMajorFactorColumnDefaults: () => Promise<void> | void
  parseNumberOrNull: (value: any, options?: any) => any
  getBudgetFee: (row: TRow | undefined) => number | null
  aggFunc: any
}) : ColGroupDef<TRow> => ({
  headerName: scaleT('columns.budgetFee'),
  marryChildren: true,
  children: [
    {
      headerName: scaleT('columns.consultCategoryFactor'),
      field: 'consultCategoryFactor' as any,
      colId: 'consultCategoryFactor',
      headerTooltip: scaleT('tooltip.resetConsultCategoryFactor'),
      headerComponent: options.headerComponent,
      headerComponentParams: {
        onReset: options.restoreConsultCategoryFactorColumnDefaults,
        resetTitle: scaleT('tooltip.resetConsultCategoryFactor')
      },
      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 => options.parseNumberOrNull(params.newValue, { precision: 3 }),
      valueFormatter: params => formatScaleEditableNumber(params)
    },
    {
      headerName: scaleT('columns.majorFactor'),
      field: 'majorFactor' as any,
      colId: 'majorFactor',
      headerTooltip: scaleT('tooltip.resetMajorFactor'),
      headerComponent: options.headerComponent,
      headerComponentParams: {
        onReset: options.restoreMajorFactorColumnDefaults,
        resetTitle: scaleT('tooltip.resetMajorFactor')
      },
      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 => options.parseNumberOrNull(params.newValue, { precision: 3 }),
      valueFormatter: params => formatScaleEditableNumber(params)
    },
    {
      headerName: scaleT('columns.workStageFactor'),
      field: 'workStageFactor' as any,
      colId: '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 => options.parseNumberOrNull(params.newValue, { precision: 3 }),
      valueFormatter: params => formatScaleEditableNumber(params)
    },
    {
      headerName: scaleT('columns.workRatio'),
      field: 'workRatio' as any,
      colId: '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 => options.parseNumberOrNull(params.newValue, { precision: 2 }),
      valueFormatter: params => formatScaleEditableNumber(params, 2)
    },
    {
      headerName: scaleT('columns.total'),
      field: 'budgetFee' as any,
      colId: 'budgetFeeTotal',
      headerClass: 'ag-right-aligned-header',
      minWidth: 120,
      flex: 1,
      aggFunc: options.aggFunc,
      cellClassRules: {
        'ag-right-aligned-cell': () => true
      },
      valueGetter: params => (params.node?.rowPinned ? (params.data as any)?.budgetFee ?? null : options.getBudgetFee(params.data)),
      valueFormatter: formatScaleReadonlyMoney
    }
  ]
})

export const createScaleRemarkColumn = <TRow>() : ColDef<TRow> => ({
  headerName: scaleT('columns.remark'),
  field: 'remark' as any,
  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 scaleT('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 === '')
  }
})

export const createScaleAutoGroupColumn = <TRow>(options: {
  totalLabel: string
  idLabelMap: Map<string, string>
  parseProjectIndexFromPathKey: (key: string) => number | null
}) : ColDef<TRow> => ({
  headerName: scaleT('columns.number'),
  minWidth: 250,
  flex: 2,
  wrapText: true,
  autoHeight: true,
  cellStyle: {
    whiteSpace: 'normal',
    lineHeight: '1.4'
  },
  cellRendererParams: {
    suppressCount: true
  },
  colSpan: getScaleMergeColSpanBeforeTotal,
  valueFormatter: params => {
    if (params.node?.rowPinned) {
      return options.totalLabel
    }
    const rowData = params.data as any
    if (!params.node?.group && rowData?.majorCode) {
      return rowData.majorCode
    }
    const nodeId = String(params.value || '')
    const projectIndex = options.parseProjectIndexFromPathKey(nodeId)
    if (projectIndex != null) return scaleT('projectLabel', { index: projectIndex })
    return options.idLabelMap.get(nodeId) || nodeId
  },
  tooltipValueGetter: params => {
    if (params.node?.rowPinned) return options.totalLabel
    const rowData = params.data as any
    if (!params.node?.group && rowData?.majorCode) {
      return rowData.majorCode
    }
    const nodeId = String(params.value || '')
    const projectIndex = options.parseProjectIndexFromPathKey(nodeId)
    if (projectIndex != null) return scaleT('projectLabel', { index: projectIndex })
    return options.idLabelMap.get(nodeId) || nodeId
  }
})

export const createScaleCalculationFormulaColumnGroup = <TRow>(options: {
  getCalculationBase?: (row: TRow | undefined) => string | null
  getCalculationBaseValue?: (row: TRow | undefined) => number | null
  getCalculationFormula?: (row: TRow | undefined) => string | null
  getCalculationAmount?: (row: TRow | undefined) => number | null
  isBaseEditable?: (row: TRow | undefined) => boolean
  parseNumberOrNull: (value: any, options?: any) => any
}) : ColGroupDef<TRow> => ({
  headerName: scaleT('columns.calculationGroup'),
  marryChildren: true,
  children: [
    {
      headerName: scaleT('columns.base'),
      field: 'calculationBase' as any,
      colId: 'calculationBase',
      minWidth: 120,
      flex: 1,
      editable: params => !params.node?.group && !params.node?.rowPinned && (options.isBaseEditable?.(params.data) ?? true),
      cellClass: params =>
        !params.node?.group && !params.node?.rowPinned && (options.isBaseEditable?.(params.data) ?? true)
          ? 'editable-cell-line'
          : '',
      cellClassRules: {
        'ag-right-aligned-cell': () => true,
        'editable-cell-empty': params =>
          !params.node?.group && !params.node?.rowPinned && (options.isBaseEditable?.(params.data) ?? true) && (params.value == null || params.value === '')
      },
      valueGetter: params => (params.node?.rowPinned ? null : options.getCalculationBase?.(params.data) ?? null),
      valueParser: params => options.parseNumberOrNull(params.newValue, { precision: 3 }),
      valueFormatter: params => {
        if (params.node?.rowPinned) return ''
        const value = params.value
        return value == null || value === '' ? '' : String(value)
      }
    },
    {
      headerName: scaleT('columns.base2'),
      field: 'calculationBaseValue' as any,
      colId: 'calculationBaseValue',
      headerClass: 'ag-right-aligned-header',
      minWidth: 130,
      flex: 1,
      cellClassRules: {
        'ag-right-aligned-cell': () => true
      },
      valueGetter: params => (params.node?.rowPinned ? null : options.getCalculationBaseValue?.(params.data) ?? null),
      valueFormatter: params => {
        if (params.node?.rowPinned) return ''
        const value = params.value
        if (value == null) return ''
        return typeof value === 'number' ? value.toLocaleString() : String(value)
      }
    },
    {
      headerName: scaleT('columns.formula'),
      field: 'calculationFormula' as any,
      colId: 'calculationFormula',
      minWidth: 200,
      flex: 1.5,
      wrapText: true,
      autoHeight: true,
      cellStyle: { whiteSpace: 'normal', lineHeight: '1.4' },
      valueGetter: params => (params.node?.rowPinned ? null : options.getCalculationFormula?.(params.data) ?? null),
      valueFormatter: params => {
        if (params.node?.rowPinned) return ''
        return params.value || ''
      }
    },
    {
      headerName: scaleT('columns.calculationAmount'),
      field: 'calculationAmount' as any,
      colId: 'calculationAmount',
      headerClass: 'ag-right-aligned-header',
      minWidth: 120,
      flex: 1,
      cellClassRules: {
        'ag-right-aligned-cell': () => true
      },
      valueGetter: params => (params.node?.rowPinned ? null : options.getCalculationAmount?.(params.data) ?? null),
      valueFormatter: params => {
        if (params.node?.rowPinned) return ''
        const value = params.value
        if (value == null) return ''
        return typeof value === 'number' ? value.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 }) : String(value)
      }
    }
  ]
})
