const storageAccessProtocol = require('../../protocols/storage-access/index.js')
const settingsService = require('../../store/settings-store.js')
const {
  AREA
} = storageAccessProtocol
const {
  bytesToHex,
  bytesToUtf8Text,
  stringToUtf8Bytes
} = require('../../utils/binary-utils.js')

const LOG_MODE_OPTIONS = [
  { key: 'hex', label: 'HEX' },
  { key: 'text', label: '文本' }
]

const STORAGE_ACCESS_COMMAND_OPTIONS = [
  { key: 'sync', label: '同步', description: '读取 info 并同步 code' },
  { key: 'read', label: '读取', description: '按字节读取内存' },
  { key: 'write', label: '写入', description: '按字节写入内存' }
]

const STORAGE_ACCESS_AREA_OPTIONS = [
  { key: AREA.DATA, label: 'data' },
  { key: AREA.IDATA, label: 'idata' },
  { key: AREA.XDATA, label: 'xdata' },
  { key: AREA.CODE, label: 'code' }
]

function normalizeHexText(value) {
  return String(value === undefined || value === null ? '' : value)
    .replace(/0x/gi, '')
    .replace(/[\s,;:_-]/g, ' ')
    .replace(/\s+/g, ' ')
    .trim()
    .toUpperCase()
}

function validateHexText(value) {
  const text = String(value === undefined || value === null ? '' : value).trim()
  const withoutPrefix = text.replace(/0x/gi, '')
  const compact = withoutPrefix.replace(/[\s,;:_-]/g, '')

  if (!compact) return '请输入十六进制数据'
  if (/[^0-9a-fA-F\s,;:_-]/.test(withoutPrefix)) return '只支持十六进制字符'
  if (compact.length % 2 !== 0) return '十六进制长度必须为偶数'

  return ''
}

function parseHexBytes(value) {
  const compact = String(value === undefined || value === null ? '' : value)
    .trim()
    .replace(/0x/gi, '')
    .replace(/[\s,;:_-]/g, '')
  const bytes = []

  for (let index = 0; index < compact.length; index += 2) {
    bytes.push(parseInt(compact.slice(index, index + 2), 16) & 0xFF)
  }

  return bytes
}

function getSerialModeLabel(mode) {
  return mode === 'text' ? '文本' : 'HEX'
}

function getNextSerialMode(mode) {
  return mode === 'hex' ? 'text' : 'hex'
}

function getSerialModeToggleText(mode) {
  return getSerialModeLabel(getNextSerialMode(mode))
}

function getLogModeLabel(mode) {
  return mode === 'text' ? '文本' : 'HEX'
}

function getNextLogMode(mode) {
  return mode === 'hex' ? 'text' : 'hex'
}

function getLogModeToggleText(mode) {
  return getLogModeLabel(getNextLogMode(mode))
}

function normalizeSerialState(current = {}, changed = {}) {
  const next = {
    serialInputText: current.serialInputText || '',
    serialMode: current.serialMode || 'hex',
    ...changed
  }
  const mode = next.serialMode === 'text' ? 'text' : 'hex'
  const inputText = String(next.serialInputText || '')
  let errorText = ''
  let bytes = []
  let previewHex = ''

  if (inputText.trim()) {
    if (mode === 'hex') {
      errorText = validateHexText(inputText)
      if (!errorText) {
        bytes = parseHexBytes(inputText)
        previewHex = bytesToHex(bytes, ' ')
      }
    } else {
      bytes = stringToUtf8Bytes(inputText)
      previewHex = bytesToHex(bytes, ' ')
    }
  }

  return {
    serialErrorText: errorText,
    serialInputText: inputText,
    serialMode: mode,
    serialModeLabel: getSerialModeLabel(mode),
    serialModeToggleText: getSerialModeToggleText(mode),
    serialPreviewHex: previewHex,
    serialPreviewLengthText: bytes.length ? `${bytes.length} bytes` : '--'
  }
}

function formatAreaLabel(area) {
  const matched = STORAGE_ACCESS_AREA_OPTIONS.find((item) => item.key === area)
  return matched ? matched.label : 'data'
}

function buildStorageAccessPreview(commandMode, area, address, length, dataBytes) {
  try {
    if (commandMode === 'sync') {
      return bytesToHex(storageAccessProtocol.buildInfoFrame(), ' ')
    }

    if (commandMode === 'write') {
      return bytesToHex(storageAccessProtocol.buildWriteFrame(area, address, dataBytes), ' ')
    }

    return bytesToHex(storageAccessProtocol.buildReadFrame(area, address, length), ' ')
  } catch (error) {
    return ''
  }
}

function normalizeStorageAccessWordText(value, fallback) {
  const text = String(value === undefined || value === null ? '' : value).trim().replace(/^0x/i, '').toUpperCase()
  return text || fallback
}

function validateStorageAccessWordText(value, label) {
  const text = String(value || '').trim()
  if (!text) return `${label}请输入十六进制`
  if (!/^[0-9A-F]+$/i.test(text)) return `${label}只支持十六进制`
  if (text.length > 4) return `${label}最多 4 位十六进制`
  return ''
}

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

function normalizeStorageAccessState(current = {}, changed = {}) {
  const next = {
    storageAccessAreaIndex: current.storageAccessAreaIndex || 0,
    storageAccessAddress: current.storageAccessAddress || '0000',
    storageAccessCommandIndex: current.storageAccessCommandIndex || 0,
    storageAccessDataText: current.storageAccessDataText || '',
    storageAccessLength: current.storageAccessLength || '0004',
    ...changed
  }

  const command = STORAGE_ACCESS_COMMAND_OPTIONS[Number(next.storageAccessCommandIndex) || 0] || STORAGE_ACCESS_COMMAND_OPTIONS[0]
  const area = STORAGE_ACCESS_AREA_OPTIONS[Number(next.storageAccessAreaIndex) || 0] || STORAGE_ACCESS_AREA_OPTIONS[0]
  const address = normalizeStorageAccessWordText(next.storageAccessAddress, '0000')
  const length = normalizeStorageAccessWordText(next.storageAccessLength, '0004')
  const dataText = normalizeHexText(next.storageAccessDataText)
  const dataBytes = dataText ? parseHexBytes(dataText) : []
  const previewArea = area.key
  const previewAddress = parseInt(address || '0', 16)
  const previewLength = parseInt(length || '0', 16)

  let errorText = ''
  if (command.key === 'read' || command.key === 'write') {
    const addressError = validateStorageAccessWordText(address, '地址')
    const lengthError = validateStorageAccessWordText(length, '长度')
    if (addressError) {
      errorText = addressError
    } else if (lengthError) {
      errorText = lengthError
    } else if (previewLength <= 0) {
      errorText = '长度必须大于 0'
    } else if (command.key === 'write') {
      const hexError = validateHexText(next.storageAccessDataText)
      if (hexError) {
        errorText = hexError
      } else if (dataBytes.length !== previewLength) {
        errorText = `写入长度为 ${previewLength} 字节，当前数据为 ${dataBytes.length} 字节`
      }
    }
  }

  if (command.key === 'sync') {
    const previewHex = buildStorageAccessPreview('sync', AREA.INFO, 0, 4, [])

    return {
      storageAccessAddress: '0000',
      storageAccessAreaIndex: 0,
      storageAccessAreaLabel: 'info',
      storageAccessCommandIndex: next.storageAccessCommandIndex,
      storageAccessCommandLabel: command.label,
      storageAccessDataText: '',
      storageAccessErrorText: '',
      storageAccessGeneratedHex: previewHex,
      storageAccessLength: '',
      storageAccessPreviewAreaText: 'info',
      storageAccessPreviewHexText: previewHex,
      storageAccessPreviewText: 'info 0x0000 / 4 bytes',
      storageAccessSendLabel: '同步',
      storageAccessSyncInfoText: '0x0F 读取 info[0:4]'
    }
  }

  const previewHex = command.key === 'write'
    ? buildStorageAccessPreview('write', previewArea, previewAddress, previewLength, dataBytes)
    : buildStorageAccessPreview('read', previewArea, previewAddress, previewLength, dataBytes)

  return {
    storageAccessAddress: address,
    storageAccessAreaIndex: next.storageAccessAreaIndex,
    storageAccessAreaLabel: area.label,
    storageAccessCommandIndex: next.storageAccessCommandIndex,
    storageAccessCommandLabel: command.label,
    storageAccessDataText: dataText,
    storageAccessErrorText: errorText,
    storageAccessGeneratedHex: errorText ? '' : previewHex,
    storageAccessLength: length,
    storageAccessPreviewAreaText: formatAreaLabel(previewArea),
    storageAccessPreviewHexText: errorText ? '' : previewHex,
    storageAccessPreviewText: errorText
      ? '--'
      : `${formatAreaLabel(previewArea)} 0x${formatStorageAccessWordText(previewAddress)} / ${previewLength} bytes`,
    storageAccessSendLabel: command.label,
    storageAccessSyncInfoText: ''
  }
}

function getLogPayloadText(log, mode) {
  if (!log) return '--'

  if (mode === 'text') {
    const payloadText = String(log.payloadText || '').trim()
    if (payloadText) return payloadText

    const bytes = Array.isArray(log.payloadBytes) ? log.payloadBytes : []
    return bytesToUtf8Text(bytes) || String(log.payload || '').trim() || '--'
  }

  if (typeof log.payload === 'string' && log.payload) {
    return log.payload
  }

  const bytes = Array.isArray(log.payloadBytes) ? log.payloadBytes : []
  return bytes.length ? bytesToHex(bytes, ' ') : '--'
}

function decorateLogs(logs, mode) {
  return (logs || []).map((item) => ({
    ...item,
    displayText: getLogPayloadText(item, mode)
  }))
}

function getProtocolModeState(settingsState = {}) {
  const isModbusProtocol = settingsService.isModbusProtocol(settingsState.protocolMode)
  const isStorageAccessProtocol = settingsService.isStorageAccessProtocol(settingsState.protocolMode)

  return {
    isModbusProtocol,
    isStorageAccessProtocol
  }
}

function getManualStatePayload(manualState = {}) {
  const commands = Array.isArray(manualState.protocolCommands) ? manualState.protocolCommands : []
  const command = commands[Number(manualState.commandIndex) || 0] || commands[0] || {}

  return {
    ...manualState,
    protocolCommandLabel: command.label || '指令',
    protocolResponseText: manualState.protocolResponseText || '',
    protocolSendLabel: '发送',
    showProtocolMultipleButton: command.inputMode === 'multiple',
    protocolTitleText: '标准 Modbus'
  }
}

module.exports = {
  LOG_MODE_OPTIONS,
  STORAGE_ACCESS_AREA_OPTIONS,
  STORAGE_ACCESS_COMMAND_OPTIONS,
  decorateLogs,
  getLogModeToggleText,
  getManualStatePayload,
  getNextLogMode,
  getNextSerialMode,
  getProtocolModeState,
  normalizeSerialState,
  normalizeHexText,
  normalizeStorageAccessState,
  parseHexBytes,
  validateHexText
}
