const transport = require('../../transport/ble-core.js')
const {
  DATA_TYPE_OPTIONS,
  formatManualMultipleQuantity,
  getManualMultipleValueText,
  normalizeManualMultipleQuantity,
  normalizeManualMultipleValues,
  updateManualMultipleTextLength,
  updateManualMultipleType,
  updateManualMultipleValue,
  validateManualMultipleValue
} = require('./multiple-registers.js')
const {
  MODBUS_COMMANDS,
  buildGeneratedExpectedResponse: buildExpectedResponse,
  createProtocolState,
  formatGeneratedResponse,
  getCommand,
  getDefaultCommandValue,
  parseHexNumber
} = require('./frame-builder.js')

const state = {
  commandIndex: 2,
  commandRegisterQuantity: '0001',
  commandValue: '0001',
  commandValueLabel: '读取数量',
  coilEnabled: true,
  generatedHex: '',
  protocolCommands: MODBUS_COMMANDS,
  protocolDataTypeOptions: DATA_TYPE_OPTIONS,
  protocolErrorText: '',
  protocolMultipleDialog: {
    visible: false
  },
  protocolMultipleExpanded: false,
  protocolMultipleValues: [],
  protocolResponseText: '',
  protocolStatusText: '',
  registerAddress: '0000',
  showCoilValue: false,
  showCommandValue: true,
  showRegisterQuantity: false,
  slaveAddress: 'F0'
}

const subscribers = []

function setState(changedData) {
  Object.assign(state, changedData)
  subscribers.slice().forEach((subscriber) => {
    subscriber(getState())
  })
}

function getState() {
  return {
    ...state,
    protocolCommands: state.protocolCommands.slice(),
    protocolDataTypeOptions: state.protocolDataTypeOptions.slice(),
    protocolMultipleDialog: {
      ...state.protocolMultipleDialog
    },
    protocolMultipleExpanded: !!state.protocolMultipleExpanded,
    protocolMultipleValues: state.protocolMultipleValues.map((item) => ({
      ...item
    })),
    protocolStatusText: state.protocolStatusText || ''
  }
}

function subscribe(subscriber) {
  if (typeof subscriber !== 'function') return () => {}

  subscribers.push(subscriber)
  subscriber(getState())

  return () => {
    const index = subscribers.indexOf(subscriber)
    if (index >= 0) subscribers.splice(index, 1)
  }
}

function setProtocolInput(changedData) {
  const command = getCommand(changedData.commandIndex === undefined ? state.commandIndex : changedData.commandIndex)
  let nextMultipleValues = changedData.protocolMultipleValues
  let nextCommandValue = changedData.commandValue
  if (
    command.inputMode === 'multiple'
    && Object.prototype.hasOwnProperty.call(changedData, 'registerAddress')
    && !Object.prototype.hasOwnProperty.call(changedData, 'protocolMultipleValues')
  ) {
    try {
      const startAddress = parseHexNumber(changedData.registerAddress, '起始地址', 0xFFFF)
      nextMultipleValues = normalizeManualMultipleValues(
        normalizeManualMultipleQuantity(state.commandRegisterQuantity),
        state.protocolMultipleValues,
        startAddress
      )
      nextCommandValue = getManualMultipleValueText(nextMultipleValues)
    } catch (error) {}
  }
  const nextState = {
    commandIndex: state.commandIndex,
    commandRegisterQuantity: state.commandRegisterQuantity,
    slaveAddress: state.slaveAddress,
    registerAddress: state.registerAddress,
    commandValue: state.commandValue,
    coilEnabled: state.coilEnabled,
    ...changedData,
    ...(nextMultipleValues ? { protocolMultipleValues: nextMultipleValues } : {}),
    ...(nextCommandValue !== undefined ? { commandValue: nextCommandValue } : {})
  }

  setState({
    ...changedData,
    ...(nextMultipleValues ? { protocolMultipleValues: nextMultipleValues } : {}),
    ...(nextCommandValue !== undefined ? { commandValue: nextCommandValue } : {}),
    protocolResponseText: '',
    protocolStatusText: '',
    ...createProtocolState(
      nextState.commandIndex,
      nextState.slaveAddress,
      nextState.registerAddress,
      nextState.commandValue,
      nextState.coilEnabled,
      nextState.commandRegisterQuantity
    )
  })
}

function setCommandIndex(index) {
  const commandIndex = Number(index)
  const command = getCommand(commandIndex)
  let protocolMultipleValues = state.protocolMultipleValues
  let commandValue = getDefaultCommandValue(command)

  if (command.inputMode === 'multiple') {
    let startAddress = 0
    try {
      startAddress = parseHexNumber(state.registerAddress, '起始地址', 0xFFFF)
    } catch (error) {}
    protocolMultipleValues = normalizeManualMultipleValues(
      normalizeManualMultipleQuantity(state.commandRegisterQuantity),
      state.protocolMultipleValues,
      startAddress
    )
    commandValue = getManualMultipleValueText(protocolMultipleValues)
  }

  setProtocolInput({
    commandIndex,
    commandValue,
    coilEnabled: true,
    commandRegisterQuantity: state.commandRegisterQuantity,
    ...(command.inputMode === 'multiple' ? { protocolMultipleValues } : {})
  })
}

function openProtocolMultipleDialog() {
  let startAddress = 0
  try {
    startAddress = parseHexNumber(state.registerAddress, '起始地址', 0xFFFF)
  } catch (error) {
    setState({
      protocolErrorText: error.message || '起始地址无效'
    })
    return
  }

  const quantity = normalizeManualMultipleQuantity(state.commandRegisterQuantity)
  const values = normalizeManualMultipleValues(quantity, state.protocolMultipleValues, startAddress)
  setState({
    commandRegisterQuantity: formatManualMultipleQuantity(quantity),
    protocolMultipleDialog: {
      title: '写多个寄存器',
      visible: true
    },
    protocolMultipleExpanded: false,
    protocolMultipleValues: values
  })
}

function closeProtocolMultipleDialog() {
  setState({
    protocolMultipleDialog: {
      visible: false
    }
  })
}

function toggleProtocolMultipleExpanded() {
  setState({
    protocolMultipleExpanded: !state.protocolMultipleExpanded
  })
}

function setProtocolMultipleQuantity(value) {
  const quantity = normalizeManualMultipleQuantity(value)
  let startAddress = 0
  try {
    startAddress = parseHexNumber(state.registerAddress, '起始地址', 0xFFFF)
  } catch (error) {
    setState({
      commandRegisterQuantity: value,
      protocolErrorText: error.message || '起始地址无效'
    })
    return
  }
  const values = normalizeManualMultipleValues(quantity, state.protocolMultipleValues, startAddress)
  const commandValue = getManualMultipleValueText(values)

  setProtocolInput({
    commandRegisterQuantity: value,
    commandValue,
    protocolMultipleValues: values
  })
}

function setProtocolMultipleValue(index, value) {
  const values = updateManualMultipleValue(state.protocolMultipleValues, index, value)
  let startAddress = 0
  try {
    startAddress = parseHexNumber(state.registerAddress, '起始地址', 0xFFFF)
  } catch (error) {
    setState({ protocolErrorText: error.message || '起始地址无效' })
    return
  }
  const normalizedValues = normalizeManualMultipleValues(normalizeManualMultipleQuantity(state.commandRegisterQuantity), values, startAddress)
  const commandValue = getManualMultipleValueText(normalizedValues)

  setProtocolInput({
    commandValue,
    protocolMultipleValues: normalizedValues
  })
}

function setProtocolMultipleType(index, dataTypeIndex) {
  const changedValues = updateManualMultipleType(state.protocolMultipleValues, index, dataTypeIndex)
  let startAddress = 0
  try {
    startAddress = parseHexNumber(state.registerAddress, '起始地址', 0xFFFF)
  } catch (error) {
    setState({ protocolErrorText: error.message || '起始地址无效' })
    return
  }
  const values = normalizeManualMultipleValues(normalizeManualMultipleQuantity(state.commandRegisterQuantity), changedValues, startAddress)

  setProtocolInput({
    commandValue: getManualMultipleValueText(values),
    protocolMultipleValues: values
  })
}

function setProtocolMultipleTextLength(index, value) {
  const changedValues = updateManualMultipleTextLength(state.protocolMultipleValues, index, value)
  let startAddress = 0
  try {
    startAddress = parseHexNumber(state.registerAddress, '起始地址', 0xFFFF)
  } catch (error) {
    setState({ protocolErrorText: error.message || '起始地址无效' })
    return
  }
  const values = normalizeManualMultipleValues(normalizeManualMultipleQuantity(state.commandRegisterQuantity), changedValues, startAddress)

  setProtocolInput({
    commandValue: getManualMultipleValueText(values),
    protocolMultipleValues: values
  })
}

function validateProtocolMultipleValue(index, value) {
  return validateManualMultipleValue(state.protocolMultipleValues, index, value)
}

function buildGeneratedExpectedResponse() {
  return buildExpectedResponse(state)
}

async function sendGeneratedFrame() {
  if (!state.generatedHex) {
    setState({
      protocolStatusText: state.protocolErrorText || '请先生成有效帧'
    })
    return false
  }

  const expected = buildGeneratedExpectedResponse()
  setState({
    protocolResponseText: '',
    protocolStatusText: ''
  })

  const response = await transport.enqueueSendFrame(state.generatedHex, 'RTU', expected ? {
    expected
  } : {})

  if (response) {
    setState({
      protocolResponseText: formatGeneratedResponse(response),
      protocolStatusText: ''
    })
  } else {
    setState({
      protocolStatusText: '未收到回复'
    })
  }

  return response
}

setState(createProtocolState(
  state.commandIndex,
  state.slaveAddress,
  state.registerAddress,
  state.commandValue,
  state.coilEnabled,
  state.commandRegisterQuantity
))

module.exports = {
  buildGeneratedExpectedResponse,
  closeProtocolMultipleDialog,
  formatGeneratedResponse,
  getState,
  openProtocolMultipleDialog,
  sendGeneratedFrame,
  setCommandIndex,
  setProtocolInput,
  setProtocolMultipleQuantity,
  setProtocolMultipleTextLength,
  setProtocolMultipleType,
  setProtocolMultipleValue,
  subscribe,
  toggleProtocolMultipleExpanded,
  validateProtocolMultipleValue
}
