import { PositionType, Data } from './type'

// 缓存列表初始化信息
const initPositinoCache = (reaItemSize: number, length = 0): PositionType[] => {
  let index = 0
  const positions: PositionType[] = Array(length)
  while (index < length) {
    positions[index] = {
      index,
      height: reaItemSize,
      width: reaItemSize,
      top: index * reaItemSize,
      bottom: (index + 1) * reaItemSize,
      left: index * reaItemSize,
      right: (index + 1) * reaItemSize,
    }
    index++
  }
  return positions
}
// 获取列表总高度
const getListTotalSize = (
  positions: Array<PositionType>,
  horizontal: true | false
): number => {
  const index = positions.length - 1
  let size = 0
  if (index < 0) {
    size = 0
  } else {
    size = horizontal ? positions[index].right : positions[index].bottom
  }
  return size
}
// 通过二分法找到 scrollOffset 对应的值
const binarySearch = (
  positionsList: Array<PositionType>,
  value = 0,
  horizontal: true | false
): number => {
  let start = 0
  let end: number = positionsList.length - 1
  let tempIndex = null
  const key = horizontal ? 'right' : 'bottom'
  while (start <= end) {
    const midIndex = Math.floor((start + end) / 2)
    const midValue = positionsList[midIndex][key]

    // 相等则直接返回（因为是bottom, 因此startIndex应该是下一个节点）
    if (midValue === value) {
      return midIndex + 1
    }
    // 中间值 < 传入值，则说明 value对应的节点 大于 start, start往后移动一位
    if (midValue < value) {
      start = midIndex + 1
    }
    // 中间值 > 传入值，则说明 value 在 中间值之前，end 节点移动到 mid - 1
    else if (midValue > value) {
      // tempIndex存放最靠近值为value的所有
      if (tempIndex === null || tempIndex > midIndex) {
        tempIndex = midIndex
      }
      end = midIndex - 1
    }
  }
  tempIndex = tempIndex || 0
  return tempIndex
}
const getEndIndex = ({
  sourceData,
  startIndex,
  visibleCount,
  itemEqualSize = true,
  positions,
  offSetSize,
  overscan,
  sizeKey = 'width',
}: {
  sourceData: Array<Data>
  startIndex: number
  visibleCount: number
  itemEqualSize?: boolean
  positions: PositionType[]
  offSetSize: number
  overscan: number
  sizeKey?: 'width' | 'height'
}): number => {
  const dataLength = sourceData.length
  let tempIndex = null
  if (itemEqualSize) {
    const endIndex = startIndex + visibleCount
    tempIndex = dataLength > 0 ? Math.min(dataLength, endIndex) : endIndex
  } else {
    let sizeNum = 0
    for (let i = startIndex; i < dataLength; i++) {
      sizeNum += positions[i][sizeKey] || 0
      if (sizeNum > offSetSize) {
        const endIndex = i + overscan
        tempIndex = dataLength > 0 ? Math.min(dataLength, endIndex) : endIndex
        break
      }
    }
    if (sizeNum < offSetSize) {
      tempIndex = dataLength
    }
  }
  tempIndex = tempIndex || 0
  return tempIndex
}

// 更新Item大小
const updateItemSize = (
  positions: PositionType[],
  items: HTMLCollection,
  sizeKey: 'width' | 'height'
): void => {
  const newPos = positions.concat()
  Array.from(items).forEach((item) => {
    const index = Number(item.getAttribute('data-index'))
    const styleVal = item.getAttribute('style')
    if (styleVal && styleVal.includes('none')) return
    const nowSize = item.getBoundingClientRect()[sizeKey]

    const oldSize = positions[index][sizeKey] as number
    // 存在差值, 更新该节点以后所有的节点
    const dValue = oldSize - nowSize
    if (dValue) {
      if (sizeKey === 'width') {
        newPos[index].right -= dValue
        newPos[index][sizeKey] = nowSize
        for (let k = index + 1; k < positions.length; k++) {
          newPos[k].left = positions[k - 1].right
          newPos[k].right -= dValue
        }
      } else if (sizeKey === 'height') {
        newPos[index].bottom -= dValue
        newPos[index][sizeKey] = nowSize
        for (let k = index + 1; k < positions.length; k++) {
          newPos[k].top = positions[k - 1].bottom
          newPos[k].bottom -= dValue
        }
      }
    }
  })
}

export {
  initPositinoCache,
  getListTotalSize,
  binarySearch,
  getEndIndex,
  updateItemSize,
}
