const {
  toFiniteNumber
} = require('../utils/number-format.js')
const {
  clampInteger
} = require('../utils/base-utils.js')
const {
  getWxApi
} = require('../utils/platform-utils.js')

const STORAGE_KEY = 'app-settings'
const PROTOCOL_MODE = {
  MODBUS_RTU: 'modbus-rtu',
  STORAGE_ACCESS: 'storage-access'
}
const LEGACY_PROTOCOL_MODE_ALIASES = {
  generic: PROTOCOL_MODE.MODBUS_RTU,
  private: PROTOCOL_MODE.STORAGE_ACCESS
}
const PROTOCOL_OPTIONS = [
  { key: PROTOCOL_MODE.STORAGE_ACCESS, label: '存储访问' },
  { key: PROTOCOL_MODE.MODBUS_RTU, label: '标准Modbus' }
]
const DEFAULT_SETTINGS = {
  modbusSlaveAddress: 'F0',
  nightModeEnabled: false,
  nightModeFollowSystem: true,
  parameterAutoPollEnabled: false,
  parameterMaxPacketLength: 64,
  parameterPollInterval: 100,
  protocolMode: PROTOCOL_MODE.STORAGE_ACCESS
}
const STATUS_POLL_MIN_INTERVAL = 100
const STATUS_POLL_MAX_INTERVAL = 3000
const PARAMETER_MIN_PACKET_LENGTH = 32

const state = {
  ...DEFAULT_SETTINGS
}

let initialized = false
const subscribers = []

function normalizeHexByte(value, fallback = DEFAULT_SETTINGS.modbusSlaveAddress) {
  const fallbackText = String(fallback || DEFAULT_SETTINGS.modbusSlaveAddress).toUpperCase()
  const text = String(value === undefined || value === null ? '' : value).trim()
  const hexText = text.toUpperCase().startsWith('0X') ? text.slice(2) : text

  if (!/^[0-9A-F]{1,2}$/i.test(hexText)) return fallbackText

  return parseInt(hexText, 16).toString(16).toUpperCase().padStart(2, '0')
}

function normalizeParameterPacketLength(value, fallback = DEFAULT_SETTINGS.parameterMaxPacketLength) {
  const numberValue = toFiniteNumber(value, NaN)
  if (!Number.isFinite(numberValue)) return fallback

  const rounded = Math.round(numberValue)
  if (rounded <= 0) return 0

  return Math.max(rounded, PARAMETER_MIN_PACKET_LENGTH)
}

function normalizeProtocolMode(value) {
  const key = String(value || '').trim()
  const normalizedKey = LEGACY_PROTOCOL_MODE_ALIASES[key] || key
  const matched = PROTOCOL_OPTIONS.find((option) => option.key === key)

  if (matched) return matched.key

  const normalizedMatched = PROTOCOL_OPTIONS.find((option) => option.key === normalizedKey)
  return normalizedMatched ? normalizedMatched.key : DEFAULT_SETTINGS.protocolMode
}

function isModbusProtocol(value = state.protocolMode) {
  return normalizeProtocolMode(value) === PROTOCOL_MODE.MODBUS_RTU
}

function isStorageAccessProtocol(value = state.protocolMode) {
  return normalizeProtocolMode(value) === PROTOCOL_MODE.STORAGE_ACCESS
}

function parseHexByte(value, label = '从机地址') {
  const text = String(value === undefined || value === null ? '' : value).trim()
  const hexText = text.toUpperCase().startsWith('0X') ? text.slice(2) : text

  if (!/^[0-9A-F]{1,2}$/i.test(hexText)) {
    throw new Error(`${label}需为 00 - FF`)
  }

  return parseInt(hexText, 16)
}

function migrateLegacySettings(settings = {}) {
  const hasProtocolMode = settings.protocolMode !== undefined && settings.protocolMode !== null && settings.protocolMode !== ''
  const hasParameterAutoPollEnabled = settings.parameterAutoPollEnabled !== undefined
  const hasParameterMaxPacketLength = settings.parameterMaxPacketLength !== undefined
  const hasParameterPollInterval = settings.parameterPollInterval !== undefined

  return {
    ...settings,
    protocolMode: hasProtocolMode ? settings.protocolMode : settings.modbusProtocolMode,
    parameterAutoPollEnabled: hasParameterAutoPollEnabled
      ? settings.parameterAutoPollEnabled
      : settings.genericModbusAutoPollEnabled,
    parameterMaxPacketLength: hasParameterMaxPacketLength
      ? settings.parameterMaxPacketLength
      : settings.genericModbusMaxPacketLength,
    parameterPollInterval: hasParameterPollInterval
      ? settings.parameterPollInterval
      : settings.genericModbusPollInterval
  }
}

function normalizeSettings(settings = {}) {
  const migratedSettings = migrateLegacySettings(settings)
  const protocolMode = normalizeProtocolMode(migratedSettings.protocolMode)
  const parameterAutoPollEnabled = !!migratedSettings.parameterAutoPollEnabled
  const parameterMaxPacketLength = normalizeParameterPacketLength(
    migratedSettings.parameterMaxPacketLength,
    DEFAULT_SETTINGS.parameterMaxPacketLength
  )
  const parameterPollInterval = clampInteger(
    migratedSettings.parameterPollInterval,
    STATUS_POLL_MIN_INTERVAL,
    STATUS_POLL_MAX_INTERVAL,
    DEFAULT_SETTINGS.parameterPollInterval
  )

  return {
    modbusSlaveAddress: normalizeHexByte(migratedSettings.modbusSlaveAddress),
    nightModeEnabled: !!migratedSettings.nightModeEnabled,
    nightModeFollowSystem: migratedSettings.nightModeFollowSystem !== false,
    parameterAutoPollEnabled,
    parameterMaxPacketLength,
    parameterPollInterval,
    protocolMode
  }
}

function readStoredSettings() {
  const wxApi = getWxApi()
  if (typeof wxApi.getStorageSync !== 'function') return {}

  try {
    return wxApi.getStorageSync(STORAGE_KEY) || {}
  } catch (error) {
    return {}
  }
}

function persistSettings() {
  const wxApi = getWxApi()
  if (typeof wxApi.setStorageSync !== 'function') return

  try {
    wxApi.setStorageSync(STORAGE_KEY, getState())
  } catch (error) {}
}

function notify() {
  const nextState = getState()

  subscribers.slice().forEach((subscriber) => {
    subscriber(nextState)
  })
}

function setState(changedData, options = {}) {
  Object.assign(state, normalizeSettings({
    ...state,
    ...changedData
  }))

  if (options.persist !== false) {
    persistSettings()
  }

  notify()
}

function init() {
  if (initialized) return

  Object.assign(state, normalizeSettings(readStoredSettings()))
  initialized = true
}

function getState() {
  return {
    ...state
  }
}

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

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

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

function setNightModeEnabled(value) {
  init()
  setState({
    nightModeEnabled: !!value
  })
}

function setNightModeFollowSystem(value) {
  init()
  setState({
    nightModeFollowSystem: !!value
  })
}

function setModbusSlaveAddress(value) {
  init()
  setState({
    modbusSlaveAddress: normalizeHexByte(value, state.modbusSlaveAddress)
  })
}

function setProtocolMode(value) {
  init()
  setState({
    protocolMode: normalizeProtocolMode(value)
  })
}

function getModbusSlaveAddress() {
  init()
  return parseHexByte(state.modbusSlaveAddress, 'Modbus从机地址')
}

function setParameterAutoPollEnabled(value) {
  init()
  setState({
    parameterAutoPollEnabled: !!value
  })
}

function setParameterMaxPacketLength(value) {
  init()
  setState({
    parameterMaxPacketLength: normalizeParameterPacketLength(value, state.parameterMaxPacketLength)
  })
}

function setParameterPollInterval(value) {
  init()
  setState({
    parameterPollInterval: value
  })
}

module.exports = {
  PARAMETER_MIN_PACKET_LENGTH,
  PROTOCOL_MODE,
  PROTOCOL_OPTIONS,
  STATUS_POLL_MAX_INTERVAL,
  STATUS_POLL_MIN_INTERVAL,
  getModbusSlaveAddress,
  getState,
  init,
  isModbusProtocol,
  isStorageAccessProtocol,
  setModbusSlaveAddress,
  setNightModeEnabled,
  setNightModeFollowSystem,
  setParameterAutoPollEnabled,
  setParameterMaxPacketLength,
  setParameterPollInterval,
  setProtocolMode,
  subscribe
}
