import type { SpanRect } from '../../interfaces'
import { internals } from '../../internals'
import { isLeafNode, makeRecursiveMapper } from '../../utils'
import { TablePipeline } from '../pipeline'

function isIdentity(x: any, y: any, prevRow: any, row: any, keys?: string[]) {
  if (Array.isArray(keys) && keys.length) {
    const prevValues = keys.map((key) => prevRow[key]).join('_')
    const values = keys.map((key) => row[key]).join('_')
    return prevValues === values
  }
  return x === y
}

export function autoRowSpan() {
  return function autoRowSpanStep(pipeline: TablePipeline) {
    const dataSource = pipeline.getDataSource()

    return pipeline.mapColumns(
      makeRecursiveMapper((col, { startIndex, endIndex }) => {
        // 如果是分组列节点，不做处理
        if (!col.features?.autoRowSpan || typeof col.groupIndex === 'number' || col.isDragColumn) {
          return col
        }
        if (!isLeafNode(col)) {
          return col
        }
        /**判断哪些值相等才进行合并*/
        const keys = col.features.autoRowSpanKeys as string[]
        const shouldMergeCell = typeof col.features.autoRowSpan === 'function' ? col.features.autoRowSpan : isIdentity

        const spanRects: SpanRect[] = []
        let lastBottom = 0
        let prevValue: any = null
        let prevRow: any = null

        for (let rowIndex = 0; rowIndex < dataSource.length; rowIndex++) {
          const row = dataSource[rowIndex]
          const value = internals.safeGetValue(col, row, rowIndex)

          if (rowIndex === 0 || !shouldMergeCell(prevValue, value, prevRow, row, keys)) {
            const spanRect: SpanRect = {
              top: lastBottom,
              bottom: rowIndex,
              left: startIndex,
              right: endIndex,
            }
            for (let i = lastBottom; i < rowIndex; i++) {
              spanRects.push(spanRect)
            }
            lastBottom = rowIndex
          }
          prevValue = value
          prevRow = row
        }

        for (let i = lastBottom; i < dataSource.length; i++) {
          spanRects.push({
            top: lastBottom,
            bottom: dataSource.length,
            left: startIndex,
            right: endIndex,
          })
        }

        return {
          ...col,
          getSpanRect(value: any, row: any, rowIndex: number) {
            return spanRects[rowIndex]
          },
        }
      }),
    )
  }
}
