const {
  clampInteger,
  getWxApi,
  toFiniteNumber
} = require('../utils/base-utils.js')
const {
  normalizeHexByte,
  parseHexByte
} = require('../utils/validation.js')
const {
  DEFAULT_PROTOCOL_MODE,
  PROTOCOL_MODE,
  PROTOCOL_OPTIONS,
  isModbusProtocolMode,
  isNoProtocolMode,
  isStorageAccessProtocolMode,
  normalizeProtocolMode
} = require('../domain/protocol-mode.js')

const STORAGE_KEY = 'app-settings'
const DEFAULT_SETTINGS = {
  modbusSlaveAddress: 'F0',
  nightModeEnabled: false,
  nightModeFollowSystem: true,
  parameterAutoPollEnabled: false,
  parameterMaxPacketLength: 64,
  parameterPollInterval: 100,
  protocolMode: DEFAULT_PROTOCOL_MODE
}
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 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 isModbusProtocol(value = state.protocolMode) {
  return isModbusProtocolMode(value)
}

function isStorageAccessProtocol(value = state.protocolMode) {
  return isStorageAccessProtocolMode(value)
}

function isNoProtocol(value = state.protocolMode) {
  return isNoProtocolMode(value)
}

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

  return {
    modbusSlaveAddress: normalizeHexByte(settings.modbusSlaveAddress),
    nightModeEnabled: !!settings.nightModeEnabled,
    nightModeFollowSystem: settings.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,
  isNoProtocol,
  isModbusProtocol,
  isStorageAccessProtocol,
  setModbusSlaveAddress,
  setNightModeEnabled,
  setNightModeFollowSystem,
  setParameterAutoPollEnabled,
  setParameterMaxPacketLength,
  setParameterPollInterval,
  setProtocolMode,
  normalizeProtocolMode,
  subscribe
}
