const parameterGroupService = require('./service.js')
const {
  validateValueFormula
} = require('../../domain/parameter-groups/value-formula.js')
const settingsService = require('../../store/settings-store.js')
const themeService = require('../../store/theme-store.js')
const transport = require('../../transport/ble-core.js')

function getOption(options, index) {
  return options[Number(index)] || options[0] || {}
}

function getCodeInfoVariableByteLength(dialog = {}) {
  const entryKind = String(dialog.sourceEntryKind || '').trim().toLowerCase()
  const byteLength = Number(dialog.sourceByteLength)

  if (entryKind !== 'variable' || !Number.isFinite(byteLength) || byteLength <= 0) return 0

  return Math.floor(byteLength)
}

function getDataTypeConfigByteLength(dataType = {}, dialog = {}) {
  if (dataType.kind === 'raw') return getCodeInfoVariableByteLength(dialog)
  if (dataType.kind === 'text') return Number(dialog.textByteLength) || Number(dataType.byteLength) || 0

  return Number(dataType.byteLength) || Number(dataType.wordCount || 0) * 2
}

function validateCodeInfoVariableDataType(dialog = {}, dataType = {}) {
  const sourceByteLength = getCodeInfoVariableByteLength(dialog)
  if (!sourceByteLength || dataType.kind === 'raw') return

  if (dataType.kind === 'text' || dataType.kind === 'hex') {
    throw new Error('单独变量类型请选择有符号/无符号整数、float 或 enum 对应整数类型')
  }

  const dataTypeByteLength = getDataTypeConfigByteLength(dataType, dialog)
  if (dataTypeByteLength !== sourceByteLength) {
    throw new Error(`单独变量 TLV 长度为 ${sourceByteLength}B，不能选择 ${dataType.label || dataType.key || '该类型'}`)
  }
}

function getPageState() {
  const settingsState = settingsService.getState()
  const transportState = transport.getState()
  const isNoProtocol = settingsService.isNoProtocol(settingsState.protocolMode)
  const isModbusProtocol = settingsService.isModbusProtocol(settingsState.protocolMode)
  const isStorageAccessProtocol = settingsService.isStorageAccessProtocol(settingsState.protocolMode)

  return {
    ...parameterGroupService.getState(),
    ...themeService.getState(),
    ...settingsState,
    connectedDevice: transportState.connectedDevice,
    isNoProtocol,
    isModbusProtocol,
    isStorageAccessProtocol
  }
}

function resolveActiveParamView(currentView) {
  return currentView === 'parameterGroup' ? currentView : 'parameterGroups'
}

function getSettingsPageState(currentData, settingsState) {
  const isNoProtocol = settingsService.isNoProtocol(settingsState.protocolMode)
  const isModbusProtocol = settingsService.isModbusProtocol(settingsState.protocolMode)
  const isStorageAccessProtocol = settingsService.isStorageAccessProtocol(settingsState.protocolMode)

  return {
    ...settingsState,
    activeParamView: resolveActiveParamView(currentData.activeParamView),
    isNoProtocol,
    isModbusProtocol,
    isStorageAccessProtocol
  }
}

function getVisiblePageState(currentData) {
  const settingsState = settingsService.getState()
  const transportState = transport.getState()
  const isNoProtocol = settingsService.isNoProtocol(settingsState.protocolMode)
  const isModbusProtocol = settingsService.isModbusProtocol(settingsState.protocolMode)
  const isStorageAccessProtocol = settingsService.isStorageAccessProtocol(settingsState.protocolMode)
  const pageState = {
    ...parameterGroupService.getState(),
    ...themeService.getState(),
    ...settingsState,
    connectedDevice: transportState.connectedDevice,
    isNoProtocol,
    isModbusProtocol,
    isStorageAccessProtocol
  }

  return {
    ...pageState,
    activeParamView: resolveActiveParamView(currentData.activeParamView)
  }
}

function getTransportPageState(transportState = transport.getState()) {
  return {
    connectedDevice: transportState.connectedDevice
  }
}

function createParameterDialogState(overrides = {}) {
  const registerType = getOption(parameterGroupService.REGISTER_TYPE_OPTIONS, 0)
  const dataType = getOption(parameterGroupService.DATA_TYPE_OPTIONS, 0)

  return {
    cancelText: '取消',
    confirmText: '确认',
    dataTypeIndex: 0,
    dataTypeText: dataType.label || '',
    groupId: '',
    groupName: '',
    mode: '',
    name: '',
    quantity: '1',
    registerIndex: -1,
    registerTypeIndex: 0,
    registerTypeText: registerType.label || '',
    remark: '',
    startAddress: '0000',
    title: '',
    textByteLength: '32',
    showTextLength: false,
    unit: '',
    visible: false,
    maxValue: '',
    minValue: '',
    conversionFormula: '',
    conversionFormulaErrorText: '',
    addressText: '',
    displayValue: '',
    rawValueText: '',
    showDataType: false,
    showRange: false,
    showUnit: false,
    readOnly: false,
    parsedStructRegisters: [],
    pollEnabled: true,
    showPollEnabled: false,
    sourceByteLength: '',
    sourceEntryKind: '',
    structDefinition: '',
    structParsedSummary: '',
    ...overrides
  }
}

function createParameterGroupDialogState(group) {
  const isEdit = !!group
  const isStorageGroup = !!(group && group.sourceMemoryArea)
  const registerTypeIndex = isEdit ? (group.registerTypeIndex || 0) : 0
  const registerType = getOption(parameterGroupService.REGISTER_TYPE_OPTIONS, registerTypeIndex)
  return createParameterDialogState({
    confirmText: isEdit ? '保存' : '确认',
    groupId: isEdit ? group.id : '',
    groupName: isEdit ? group.name : (isStorageGroup ? '结构体组' : '寄存器组'),
    layout: isEdit ? (group.layout || 'register') : 'register',
    mode: isEdit ? 'editGroup' : 'createGroup',
    quantity: isEdit ? String(group.quantity || 1) : '1',
    pollEnabled: isEdit ? group.pollEnabled !== false : true,
    registerTypeIndex,
    registerTypeText: registerType.label || '',
    showPollEnabled: true,
    startAddress: isEdit && group.startAddressText ? group.startAddressText.replace(/^0x/i, '') : '0000',
    title: isStorageGroup
      ? (isEdit ? '编辑结构体组' : '添加结构体组')
      : (isEdit ? '编辑寄存器组' : '添加寄存器组'),
    visible: true
  })
}

function createParameterRegisterDialogState(mode, group, register, registerIndex) {
  const isView = mode === 'viewRegister'
  const dataTypeIndex = register.dataTypeIndex || 0
  const dataType = getOption(parameterGroupService.DATA_TYPE_OPTIONS, dataTypeIndex)

  return createParameterDialogState({
    cancelText: isView ? '关闭' : '取消',
    confirmText: isView ? '' : '保存',
    dataTypeIndex,
    dataTypeText: register.dataTypeText || dataType.label || '',
    groupId: group.id,
    groupName: group.name,
    mode,
    name: register.name,
    registerIndex,
    registerTypeIndex: group.registerTypeIndex || 0,
    remark: register.remark || '',
    startAddress: group.startAddressText ? group.startAddressText.replace(/^0x/i, '') : '0000',
    title: isView ? '寄存器信息' : '寄存器配置',
    textByteLength: String(register.textByteLength || '32'),
    showTextLength: !!register.showTextLength,
    unit: register.unit || '',
    visible: true,
    conversionFormula: register.conversionFormula || '',
    conversionFormulaErrorText: register.conversionFormulaErrorText || '',
    maxValue: register.maxValue || '',
    minValue: register.minValue || '',
    addressText: register.addressRangeText || register.addressText || '',
    displayValue: register.displayValue || '',
    rawValueText: register.rawValueText || '--',
    sourceByteLength: register.sourceByteLength || '',
    sourceEntryKind: register.sourceEntryKind || '',
    sourceMetaText: register.sourceMetaText || '',
    showDataType: !!register.showDataType,
    showRange: !!register.showRange,
    showUnit: !!register.showUnit,
    readOnly: isView
  })
}

function getDialogDataTypeState(dialog, dataTypeOptions, dataTypeIndex) {
  const dataType = getOption(dataTypeOptions, dataTypeIndex)
  const isTextType = dataType.kind === 'text'
  const showUnit = dataType.kind === 'number' && dataType.key !== 'hex'

  return {
    dataTypeIndex,
    dataTypeText: dataType.label || '',
    maxValue: isTextType ? '' : dialog.maxValue,
    minValue: isTextType ? '' : dialog.minValue,
    showRange: !isTextType,
    showTextLength: isTextType,
    showUnit,
    textByteLength: isTextType ? (dialog.textByteLength || '32') : dialog.textByteLength,
    unit: showUnit ? dialog.unit : ''
  }
}

function createParameterGroupConfig(dialog) {
  const registers = Array.isArray(dialog.parsedStructRegisters)
    ? dialog.parsedStructRegisters
    : []

  return {
    groupName: dialog.groupName,
    layout: registers.length ? 'struct' : (dialog.layout || 'register'),
    pollEnabled: dialog.pollEnabled !== false,
    quantity: registers.length ? String(registers.length) : dialog.quantity,
    registerTypeIndex: dialog.registerTypeIndex,
    startAddress: dialog.startAddress,
    ...(registers.length ? {
      registers: registers.map((register) => ({
        bitOffset: register.bitOffset,
        bitWidth: register.bitWidth,
        byteStart: register.byteStart,
        dataType: register.dataType,
        isBitField: !!register.isBitField,
        isStructField: true,
        name: register.name,
        structByteLength: register.structByteLength,
        textByteLength: register.textByteLength
      }))
    } : {})
  }
}

function createParameterRegisterChangedData(dialog, dataTypeOptions) {
  const dataType = getOption(dataTypeOptions, dialog.dataTypeIndex)
  const isTextType = dataType.kind === 'text'
  const showUnit = dataType.kind === 'number' && dataType.key !== 'hex'
  const conversionFormula = String(dialog.conversionFormula || '').trim()

  validateValueFormula(conversionFormula)
  validateCodeInfoVariableDataType(dialog, dataType)

  return {
    name: dialog.name,
    conversionFormula,
    dataType: dataType.key,
    maxValue: isTextType ? '' : dialog.maxValue,
    minValue: isTextType ? '' : dialog.minValue,
    remark: dialog.remark,
    textByteLength: isTextType ? dialog.textByteLength : '',
    unit: showUnit ? dialog.unit : ''
  }
}

function findParameterGroup(groups, groupId) {
  return (groups || []).find((item) => item.id === groupId) || null
}

function findParameterRegister(groups, groupId, registerIndex) {
  const group = findParameterGroup(groups, groupId)
  const register = group && group.registers ? group.registers[registerIndex] : null

  return {
    group,
    register
  }
}

function getActiveParameterGroup(groups, groupId) {
  return findParameterGroup(groups, groupId) || null
}

module.exports = {
  createParameterGroupConfig,
  createParameterGroupDialogState,
  createParameterDialogState,
  createParameterRegisterChangedData,
  createParameterRegisterDialogState,
  findParameterGroup,
  findParameterRegister,
  getActiveParameterGroup,
  getDialogDataTypeState,
  getOption,
  getPageState,
  getSettingsPageState,
  getTransportPageState,
  getVisiblePageState,
  resolveActiveParamView
}
