const {
  buildReadFrame,
  buildWriteMultipleRegistersFrame,
  buildWriteSingleCoilFrame,
  buildWriteSingleRegisterFrame,
  formatHex
} = require('../../protocols/modbus-rtu/index.js')

const MODBUS_COMMANDS = [
  { key: 'readCoils', label: '01 读取线圈', functionCode: 0x01, inputMode: 'quantity' },
  { key: 'readDiscreteInputs', label: '02 读取离散输入', functionCode: 0x02, inputMode: 'quantity' },
  { key: 'readHolding', label: '03 读取保持寄存器', functionCode: 0x03, inputMode: 'quantity' },
  { key: 'readInput', label: '04 读取输入寄存器', functionCode: 0x04, inputMode: 'quantity' },
  { key: 'writeCoil', label: '05 写单线圈', functionCode: 0x05, inputMode: 'coil' },
  { key: 'writeRegister', label: '06 写单寄存器', functionCode: 0x06, inputMode: 'single' },
  { key: 'writeRegisters', label: '10 写多寄存器', functionCode: 0x10, inputMode: 'multiple' }
]

function parseHexNumber(value, label, maxValue) {
  const text = String(value || '').trim().replace(/^0x/i, '')

  if (!text || !/^[0-9a-fA-F]+$/.test(text)) {
    throw new Error(`${label}请输入十六进制数值`)
  }

  const parsedValue = parseInt(text, 16)
  if (parsedValue > maxValue) {
    throw new Error(`${label}超出范围`)
  }

  return parsedValue
}

function parseRegisterValues(value) {
  const text = String(value || '').trim()
  if (!text) throw new Error('请输入寄存器写入值')

  return text.split(/[\s,;]+/)
    .filter(Boolean)
    .map((item) => parseHexNumber(item, '写入值', 0xFFFF))
}

function getCommand(index) {
  return MODBUS_COMMANDS[index] || MODBUS_COMMANDS[0]
}

function getDefaultCommandValue(command) {
  if (command.inputMode === 'quantity') return '0001'
  if (command.inputMode === 'coil') return 'ON'
  if (command.inputMode === 'multiple') return '0000'

  return '0000'
}

function generateModbusFrame(command, slaveAddress, registerAddress, commandValue, coilEnabled, commandRegisterQuantity) {
  const slave = parseHexNumber(slaveAddress, '从站地址', 0xFF)
  const address = parseHexNumber(registerAddress, '起始地址', 0xFFFF)

  if (command.inputMode === 'quantity') {
    const quantity = parseHexNumber(commandValue, '读取数量', 0xFFFF)
    return buildReadFrame(slave, command.functionCode, address, quantity)
  }
  if (command.inputMode === 'coil') {
    return buildWriteSingleCoilFrame(slave, address, coilEnabled)
  }
  if (command.inputMode === 'single') {
    return buildWriteSingleRegisterFrame(slave, address, parseHexNumber(commandValue, '写入值', 0xFFFF))
  }

  const words = parseRegisterValues(commandValue)
  const quantity = parseHexNumber(commandRegisterQuantity, '寄存器个数', 0xFFFF)
  if (quantity !== words.length) {
    throw new Error(`写入值数量应为 ${quantity} 个寄存器`)
  }

  return buildWriteMultipleRegistersFrame(slave, address, words)
}

function createProtocolState(commandIndex, slaveAddress, registerAddress, commandValue, coilEnabled, commandRegisterQuantity) {
  const command = getCommand(commandIndex)
  const commandValueLabel = command.inputMode === 'quantity' ? '读取数量' : '写入值'

  try {
    return {
      commandValueLabel,
      generatedHex: formatHex(generateModbusFrame(command, slaveAddress, registerAddress, commandValue, coilEnabled, commandRegisterQuantity)),
      protocolErrorText: '',
      showCoilValue: command.inputMode === 'coil',
      showRegisterQuantity: command.inputMode === 'multiple',
      showCommandValue: command.inputMode !== 'coil'
    }
  } catch (error) {
    return {
      commandValueLabel,
      generatedHex: '',
      protocolErrorText: error.message,
      showCoilValue: command.inputMode === 'coil',
      showRegisterQuantity: command.inputMode === 'multiple',
      showCommandValue: command.inputMode !== 'coil'
    }
  }
}

function buildGeneratedExpectedResponse(state = {}) {
  try {
    const command = getCommand(state.commandIndex)
    const address = parseHexNumber(state.registerAddress, '起始地址', 0xFFFF)
    const slaveAddress = parseHexNumber(state.slaveAddress, '从站地址', 0xFF)
    const quantity = command.inputMode === 'quantity'
      ? parseHexNumber(state.commandValue, '读取数量', 0xFFFF)
      : (command.inputMode === 'multiple' ? parseHexNumber(state.commandRegisterQuantity, '寄存器个数', 0xFFFF) : 1)
    const value = command.inputMode === 'coil'
      ? (state.coilEnabled ? 0xFF00 : 0x0000)
      : (command.inputMode === 'single' ? parseHexNumber(state.commandValue, '写入值', 0xFFFF) : undefined)

    return {
      address,
      functionCode: command.functionCode,
      kind: 'manual-rtu',
      protocol: 'modbus-rtu',
      quantity,
      value,
      slaveAddress
    }
  } catch (error) {
    return null
  }
}

function formatResponseHex(value, width) {
  return Number(value || 0).toString(16).toUpperCase().padStart(width, '0')
}

function formatGeneratedResponse(response) {
  if (!response) return ''

  const slave = formatResponseHex(response.slaveAddress, 2)
  const functionCode = formatResponseHex(response.functionCode, 2)

  if (Array.isArray(response.words) && response.words.length) {
    return `从机 0x${slave} / 功能码 0x${functionCode} / 字 ${response.words.map((word) => formatResponseHex(word, 4)).join(' ')}`
  }

  if (Array.isArray(response.dataBytes) && response.dataBytes.length) {
    return `从机 0x${slave} / 功能码 0x${functionCode} / 数据 ${formatHex(response.dataBytes)}`
  }

  if (Number.isInteger(response.address)) {
    return `从机 0x${slave} / 功能码 0x${functionCode} / 地址 0x${formatResponseHex(response.address, 4)} / 值 0x${formatResponseHex(response.quantityOrValue, 4)}`
  }

  return `从机 0x${slave} / 功能码 0x${functionCode}`
}

module.exports = {
  MODBUS_COMMANDS,
  buildGeneratedExpectedResponse,
  createProtocolState,
  formatGeneratedResponse,
  generateModbusFrame,
  getCommand,
  getDefaultCommandValue,
  parseHexNumber,
  parseRegisterValues
}
