const controlService = require('./control-service')
const genericModbusService = require('./generic-modbus-service')
const paramsPageState = require('./params-page-state')
const settingsService = require('./settings-service')
const syncService = require('./sync-service')
const {
  getStatusPageState
} = require('./status-page-state')
const themeService = require('./theme-service')

const GROUP_LABELS = {
  dq: 'DQ轴电流环参数',
  estimator: '估算器参数',
  oil: '上油参数',
  preposition: '预定位配置',
  protection: '保护',
  speedLoop: '速度环路',
  tailwind: '顺逆风配置',
  vsp: 'VSP曲线'
}

const COMBINED_GROUPS = {
  speed: ['speedLoop', 'vsp', 'oil'],
  startup: ['tailwind', 'preposition']
}

const COMBINED_GROUP_LABELS = {
  speed: '速度管理',
  startup: '启动位置管理'
}
const PARAM_VIEWS = [
  'driver',
  'protection',
  'estimator',
  'dq',
  'startup',
  'speed',
  'genericModbus',
  'status'
]

function getGroupLabel(groupKey) {
  return GROUP_LABELS[groupKey] || '参数'
}

function getCombinedGroupKeys(viewKey) {
  return COMBINED_GROUPS[viewKey] || []
}

function getCombinedGroupLabel(viewKey) {
  return COMBINED_GROUP_LABELS[viewKey] || '参数'
}

function hasDirtyItem(items = []) {
  return items.some((item) => !!item && !!item.isDirty)
}

function hasWritableGroupChanges(data, groupKey) {
  if (groupKey === 'tailwind') {
    return hasDirtyItem(data.tailwindSwitchRegisters) || hasDirtyItem(data.tailwindAtoBandwidthDisplayRegisters)
  }
  if (groupKey === 'preposition') {
    return hasDirtyItem(data.prepositionSwitchRegisters) || hasDirtyItem(data.prepositionParameterDisplayRegisters)
  }
  if (groupKey === 'speedLoop') {
    return hasDirtyItem(data.speedLoopInputDisplayRegisters) || hasDirtyItem(data.speedLoopExtraDisplayRegisters)
  }
  if (groupKey === 'vsp') {
    return hasDirtyItem(data.vspCurveRegisters) || !!(data.speedSlopeRegister && data.speedSlopeRegister.isDirty)
  }
  if (groupKey === 'oil') return hasDirtyItem(data.oilParameterInputRegisters)

  return false
}

function getControlViewState(controlState = controlService.getState()) {
  return {
    ...controlState,
    ...getStatusPageState(controlState.userStatusCount),
    canReadStatus: !!controlState.connectedDevice
  }
}

function getProtocolFlags(settingsState = settingsService.getState()) {
  return {
    isGenericProtocol: settingsState.modbusProtocolFilter === 'generic',
    isMotorControlProtocol: settingsState.modbusProtocolFilter !== 'generic'
  }
}

function getPageState(
  paramsState = syncService.getParamsSnapshot(),
  controlState = controlService.getState()
) {
  const settingsState = settingsService.getState()

  return {
    ...paramsPageState.refreshState(paramsState),
    ...getControlViewState(controlState),
    ...genericModbusService.getState(),
    ...themeService.getState(),
    ...settingsState,
    ...getProtocolFlags(settingsState)
  }
}

function resolveActiveParamView(currentView, settingsState) {
  if (settingsState.modbusProtocolFilter === 'generic') {
    return currentView === 'genericModbus' ? currentView : 'genericModbus'
  }

  return PARAM_VIEWS.includes(currentView) && currentView !== 'genericModbus' ? currentView : ''
}

function getSettingsPageState(currentData, settingsState) {
  const activeParamView = resolveActiveParamView(currentData.activeParamView, settingsState)

  return {
    ...settingsState,
    activeParamView,
    ...getProtocolFlags(settingsState)
  }
}

function getVisiblePageState(currentData) {
  const snapshot = syncService.getParamsSnapshot()
  const nextParamsState = snapshot.syncVersion && snapshot.syncVersion !== currentData.syncVersion
    ? paramsPageState.refreshState(snapshot)
    : paramsPageState.refreshState(currentData)
  const pageState = {
    ...nextParamsState,
    ...getControlViewState(),
    ...genericModbusService.getState(),
    ...themeService.getState(),
    ...settingsService.getState()
  }
  return {
    ...pageState,
    activeParamView: resolveActiveParamView(currentData.activeParamView, pageState),
    ...getProtocolFlags(pageState)
  }
}

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

function createGenericModbusDialogState(overrides = {}) {
  const registerType = getGenericOption(genericModbusService.REGISTER_TYPE_OPTIONS, 0)
  const dataType = getGenericOption(genericModbusService.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: '',
    addressText: '',
    displayValue: '',
    rawValueText: '',
    showDataType: false,
    showRange: false,
    showUnit: false,
    readOnly: false,
    ...overrides
  }
}

function createGenericGroupDialogState(group) {
  const isEdit = !!group
  const registerTypeIndex = isEdit ? (group.registerTypeIndex || 0) : 0
  const registerType = getGenericOption(genericModbusService.REGISTER_TYPE_OPTIONS, registerTypeIndex)

  return createGenericModbusDialogState({
    confirmText: isEdit ? '保存' : '确认',
    groupId: isEdit ? group.id : '',
    groupName: isEdit ? group.name : '寄存器组',
    mode: isEdit ? 'editGroup' : 'createGroup',
    quantity: isEdit ? String(group.quantity || 1) : '1',
    registerTypeIndex,
    registerTypeText: registerType.label || '',
    startAddress: isEdit && group.startAddressText ? group.startAddressText.replace(/^0x/i, '') : '0000',
    title: isEdit ? '编辑寄存器组' : '添加寄存器组',
    visible: true
  })
}

function createGenericRegisterDialogState(mode, group, register, registerIndex) {
  const isView = mode === 'viewRegister'
  const dataTypeIndex = register.dataTypeIndex || 0
  const dataType = getGenericOption(genericModbusService.DATA_TYPE_OPTIONS, dataTypeIndex)

  return createGenericModbusDialogState({
    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,
    maxValue: register.maxValue || '',
    minValue: register.minValue || '',
    addressText: register.addressRangeText || register.addressText || '',
    displayValue: register.displayValue || '',
    rawValueText: register.rawValueText || '--',
    showDataType: !!register.showDataType,
    showRange: !!register.showRange,
    showUnit: !!register.showUnit,
    readOnly: isView
  })
}

function getGenericDialogDataTypeState(dialog, dataTypeOptions, dataTypeIndex) {
  const dataType = getGenericOption(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 createGenericGroupConfig(dialog) {
  return {
    groupName: dialog.groupName,
    quantity: dialog.quantity,
    registerTypeIndex: dialog.registerTypeIndex,
    startAddress: dialog.startAddress
  }
}

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

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

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

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

  return {
    group,
    register
  }
}

module.exports = {
  createGenericGroupConfig,
  createGenericGroupDialogState,
  createGenericModbusDialogState,
  createGenericRegisterChangedData,
  createGenericRegisterDialogState,
  findGenericGroup,
  findGenericRegister,
  getCombinedGroupKeys,
  getCombinedGroupLabel,
  getControlViewState,
  getGenericDialogDataTypeState,
  getGenericOption,
  getGroupLabel,
  getPageState,
  getSettingsPageState,
  getVisiblePageState,
  hasWritableGroupChanges,
  resolveActiveParamView
}
