const modbusProtocol = require('./modbus-rtu/index.js')
const storageAccessProtocol = require('./storage-access/index.js')
const {
  getBootloaderResponseLength,
  isBootloaderFrame
} = require('./bootloader/index.js')
const {
  BYTE_ORDER_HIGH,
  hasValidCrc16Ccitt
} = require('../utils/crc.js')

function inspectReceivedBytes(rawBytes, context = {}) {
  if (!Array.isArray(rawBytes) || rawBytes.length < 4) return ''

  if (isBootloaderFrame(rawBytes)) {
    const expectedLength = getBootloaderResponseLength(rawBytes)
    if (expectedLength && rawBytes.length < expectedLength) return '片段'

    return hasValidCrc16Ccitt(rawBytes, { byteOrder: BYTE_ORDER_HIGH }) ? 'CRC OK' : 'CRC ERR'
  }

  const pendingProtocol = context.pendingRequest && context.pendingRequest.protocol
  if (pendingProtocol === 'storage-access') {
    return storageAccessProtocol.hasValidStorageCrc(rawBytes) ? 'CRC OK' : '片段'
  }
  if (pendingProtocol === 'modbus-rtu') {
    return modbusProtocol.hasValidCrc16Modbus(rawBytes, modbusProtocol.MODBUS_CRC_OPTIONS) ? 'CRC OK' : '片段'
  }

  if (storageAccessProtocol.hasValidStorageCrc(rawBytes)) return 'CRC OK'

  return modbusProtocol.hasValidCrc16Modbus(rawBytes, modbusProtocol.MODBUS_CRC_OPTIONS) ? 'CRC OK' : (context.pendingRequest ? '片段' : 'CRC ERR')
}

function parseSendExpected(bytes) {
  const storageExpected = storageAccessProtocol.response.parseStorageAccessRequest(bytes)
  if (storageExpected) return storageExpected

  const expected = modbusProtocol.response.parseModbusRequest(bytes)
  if (!expected) return expected
  if (expected.slaveAddress === 0x00 && [0x05, 0x06, 0x10].includes(expected.functionCode)) return null
  if (expected.slaveAddress === 0x00 && [0x01, 0x02, 0x03, 0x04].includes(expected.functionCode)) return null

  return expected
}

function getResponseBufferHint(expected) {
  if (expected && expected.protocol === 'storage-access') {
    return storageAccessProtocol.response.getReadBufferHint(expected)
  }
  if (expected && expected.protocol === 'modbus-rtu') {
    return modbusProtocol.response.getReadBufferHint(expected)
  }

  return modbusProtocol.response.getReadBufferHint(expected)
}

function readResponseFromBuffer(buffer, expected, options = {}) {
  if (expected && expected.protocol === 'storage-access') {
    return storageAccessProtocol.response.readResponseFromBuffer(buffer, expected, options)
  }
  if (expected && expected.protocol === 'modbus-rtu') {
    return modbusProtocol.response.readResponseFromBuffer(buffer, expected, options)
  }

  return modbusProtocol.response.readResponseFromBuffer(buffer, expected, options)
}

module.exports = {
  getResponseBufferHint,
  inspectReceivedBytes,
  parseSendExpected,
  readResponseFromBuffer
}
