const PARAMETER_REGISTER_DRAG_THRESHOLD_PX = 12
const PARAMETER_REGISTER_ROW_HEIGHT_RPX = 92

function clampIndex(value, min, max) {
  return Math.min(Math.max(value, min), max)
}

function getNumberOr(value, fallback) {
  const numberValue = Number(value)

  return Number.isFinite(numberValue) ? numberValue : fallback
}

function getWindowWidth() {
  try {
    if (typeof wx !== 'undefined' && wx && typeof wx.getWindowInfo === 'function') {
      const info = wx.getWindowInfo()
      if (info && Number.isFinite(info.windowWidth)) return info.windowWidth
    }
  } catch (error) {}

  try {
    if (typeof wx !== 'undefined' && wx && typeof wx.getSystemInfoSync === 'function') {
      const info = wx.getSystemInfoSync()
      if (info && Number.isFinite(info.windowWidth)) return info.windowWidth
    }
  } catch (error) {}

  return 375
}

function rpxToPx(rpx, windowWidth) {
  return Math.round(Number(rpx || 0) * Number(windowWidth || 375) / 750)
}

function getFallbackDragRowOffsetPx(windowWidth) {
  return Math.max(44, rpxToPx(PARAMETER_REGISTER_ROW_HEIGHT_RPX, windowWidth))
}

function resolveDragTargetIndex(drag, currentY, totalCount) {
  if (!drag || !Number.isInteger(totalCount) || totalCount <= 0) return 0

  const sourceIndex = clampIndex(getNumberOr(drag.index, 0), 0, totalCount - 1)
  const rowCenters = Array.isArray(drag.rowCenters) ? drag.rowCenters : []
  const sourceCenter = Number(rowCenters[sourceIndex])
  const startY = getNumberOr(drag.startY, currentY)

  if (rowCenters.length === totalCount && Number.isFinite(sourceCenter)) {
    const currentCenter = sourceCenter + (Number(currentY) - startY)
    let targetIndex = sourceIndex

    if (currentCenter >= sourceCenter) {
      for (let index = sourceIndex + 1; index < totalCount; index += 1) {
        if (currentCenter > Number(rowCenters[index])) targetIndex = index
      }
    } else {
      for (let index = sourceIndex - 1; index >= 0; index -= 1) {
        if (currentCenter < Number(rowCenters[index])) targetIndex = index
      }
    }

    return clampIndex(targetIndex, 0, totalCount - 1)
  }

  const rowOffset = Math.max(1, Number(drag.rowOffset) || 1)
  const step = Math.round((Number(currentY) - startY) / rowOffset)

  return clampIndex(sourceIndex + step, 0, totalCount - 1)
}

function buildActiveParameterRegisterRows(group, dragState) {
  if (!group || !Array.isArray(group.registers)) return []

  const drag = dragState && dragState.groupId === group.id ? dragState : null
  const activeIndex = drag ? clampIndex(getNumberOr(drag.index, 0), 0, group.registers.length - 1) : -1
  const targetIndex = drag ? clampIndex(getNumberOr(drag.targetIndex, activeIndex), 0, group.registers.length - 1) : -1
  const rowOffset = drag ? Math.max(1, Math.round(Number(drag.rowOffset) || 0)) : 0
  const translateY = drag ? Math.round(Number(drag.translateY) || 0) : 0

  return group.registers.map((register, index) => {
    const row = {
      ...register,
      sourceIndex: index,
      dragClass: '',
      dragHandleClass: '',
      dragStyle: ''
    }

    if (!drag) return row

    const isActive = index === activeIndex
    let shiftY = 0

    if (drag.moved && rowOffset) {
      if (activeIndex < targetIndex && index > activeIndex && index <= targetIndex) {
        shiftY = -rowOffset
      } else if (activeIndex > targetIndex && index >= targetIndex && index < activeIndex) {
        shiftY = rowOffset
      }
    }

    if (isActive) {
      row.dragClass = drag.moved ? 'is-dragging' : 'is-drag-armed'
      row.dragHandleClass = drag.moved ? 'is-dragging' : 'is-drag-armed'
      row.dragStyle = drag.moved
        ? `transform: translate3d(0, ${translateY}px, 0) scale(1.02); z-index: 8;`
        : 'z-index: 3;'
      return row
    }

    if (shiftY) {
      row.dragClass = shiftY > 0 ? 'is-shift-down' : 'is-shift-up'
      row.dragStyle = `transform: translate3d(0, ${shiftY}px, 0);`
    }

    return row
  })
}

module.exports = {
  PARAMETER_REGISTER_DRAG_THRESHOLD_PX,
  buildActiveParameterRegisterRows,
  clampIndex,
  getFallbackDragRowOffsetPx,
  getWindowWidth,
  resolveDragTargetIndex
}
