const {
  DATA_TYPE_OPTIONS,
  getDataType,
  getRegisterEncodedWords,
  isByteRegister,
  isTextRegister,
  normalizeRegister,
  validateRegisterValue
} = require('../../domain/parameter-groups/model.js')

function normalizeManualMultipleQuantity(value) {
  const text = String(value === undefined || value === null ? '' : value).trim()
  if (!text) return 1
  if (/^[0-9a-fA-F]+$/.test(text)) return Math.max(1, Math.min(parseInt(text, 16), 0x007B))

  const numberValue = Number(text)
  return Number.isFinite(numberValue) ? Math.max(1, Math.min(Math.round(numberValue), 0x007B)) : 1
}

function formatManualMultipleQuantity(quantity) {
  return Number(quantity || 1).toString(16).toUpperCase().padStart(4, '0')
}

function createManualMultipleRegister(index, value = {}) {
  const dataType = getDataType(value.dataType || 'hex')
  const register = normalizeRegister({
    dataType: dataType.key,
    inputValue: value.inputValue === undefined ? '' : value.inputValue,
    name: `寄存器 ${index + 1}`,
    textByteLength: value.textByteLength || (isTextRegister(dataType.key) ? '32' : '')
  }, {
    registerType: 'holding'
  }, index, Number(value.address || 0), 0)

  return {
    ...register,
    dataTypeIndex: DATA_TYPE_OPTIONS.findIndex((item) => item.key === register.dataType),
    inputValue: value.inputValue === undefined ? '' : value.inputValue
  }
}

function getManualRegisterWordCount(register) {
  return Math.max(1, Number(register && register.registerCount) || 1)
}

function normalizeManualMultipleValues(wordQuantity, values = [], startAddress = 0) {
  const result = []
  let address = Number(startAddress) || 0
  const endAddress = address + Math.max(1, Number(wordQuantity) || 1)
  let sourceIndex = 0

  while (address < endAddress) {
    const current = values[sourceIndex] || {}
    let register = createManualMultipleRegister(result.length, {
      ...current,
      address
    })
    const remainingWords = endAddress - address
    if (getManualRegisterWordCount(register) > remainingWords) {
      register = createManualMultipleRegister(result.length, {
        ...current,
        address,
        dataType: 'hex',
        inputValue: ''
      })
    }
    result.push(register)
    address += getManualRegisterWordCount(register)
    sourceIndex += 1
  }

  return result
}

function getManualMultipleWords(values = []) {
  const words = []
  values.forEach((register) => {
    if (isByteRegister(register.dataType)) {
      const registerWords = getRegisterEncodedWords(register)
      if (!Array.isArray(registerWords) || !registerWords.length) throw new Error(`${register.name} 输入值无效`)
      words.push(Number(registerWords[0]) & 0x00FF)
      return
    }

    const registerWords = getRegisterEncodedWords(register)
    if (!Array.isArray(registerWords) || !registerWords.length) throw new Error(`${register.name} 输入值无效`)
    registerWords.forEach((word) => words.push(Number(word) & 0xFFFF))
  })

  return words
}

function getManualMultipleValueText(values = []) {
  try {
    return getManualMultipleWords(values).map((word) => word.toString(16).toUpperCase().padStart(4, '0')).join(' ')
  } catch (error) {
    return ''
  }
}

function getManualMultipleDataType(dataTypeIndex) {
  return DATA_TYPE_OPTIONS[Number(dataTypeIndex)] || DATA_TYPE_OPTIONS[0]
}

function updateManualMultipleValue(values = [], index, value) {
  const registerIndex = Number(index)

  return values.map((register, currentIndex) => (
    currentIndex === registerIndex
      ? {
        ...register,
        inputValue: value
      }
      : register
  ))
}

function updateManualMultipleType(values = [], index, dataTypeIndex) {
  const registerIndex = Number(index)
  const dataType = getManualMultipleDataType(dataTypeIndex)

  return values.map((register, currentIndex) => (
    currentIndex === registerIndex
      ? createManualMultipleRegister(currentIndex, {
        ...register,
        dataType: dataType.key,
        inputValue: '',
        textByteLength: isTextRegister(dataType.key) ? (register.textByteLength || '32') : ''
      })
      : register
  ))
}

function updateManualMultipleTextLength(values = [], index, value) {
  const registerIndex = Number(index)

  return values.map((register, currentIndex) => (
    currentIndex === registerIndex
      ? createManualMultipleRegister(currentIndex, {
        ...register,
        textByteLength: value
      })
      : register
  ))
}

function validateManualMultipleValue(values = [], index, value) {
  const register = values[Number(index)]
  if (!register) return false

  return validateRegisterValue(register, value)
}

module.exports = {
  DATA_TYPE_OPTIONS,
  createManualMultipleRegister,
  formatManualMultipleQuantity,
  getManualMultipleDataType,
  getManualMultipleValueText,
  getManualMultipleWords,
  normalizeManualMultipleQuantity,
  normalizeManualMultipleValues,
  updateManualMultipleTextLength,
  updateManualMultipleType,
  updateManualMultipleValue,
  validateManualMultipleValue
}
