const {
  toFiniteNumber
} = require('./calculation-context')
const {
  clampInteger
} = require('./base-utils')
const {
  getWxApi
} = require('./platform-utils')

const STORAGE_KEY = 'app-settings'
const MODBUS_PROTOCOL_OPTIONS = [
  { key: 'motor-control', label: '电机控制协议' },
  { key: 'generic', label: '通用协议' }
]
const DEFAULT_SETTINGS = {
  genericModbusAutoPollEnabled: false,
  genericModbusMaxPacketLength: 64,
  genericModbusPollInterval: 100,
  modbusSlaveAddress: 'F0',
  modbusProtocolFilter: MODBUS_PROTOCOL_OPTIONS[0].key,
  nightModeEnabled: false,
  nightModeFollowSystem: true,
  statusPollInterval: 100,
  userStatusCount: 0
}
const STATUS_POLL_MIN_INTERVAL = 100
const STATUS_POLL_MAX_INTERVAL = 3000
const GENERIC_MODBUS_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 normalizeGenericPacketLength(value, fallback = DEFAULT_SETTINGS.genericModbusMaxPacketLength) {
  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, GENERIC_MODBUS_MIN_PACKET_LENGTH)
}

function normalizeModbusProtocolFilter(value) {
  const key = String(value || '').trim()
  const matchedOption = MODBUS_PROTOCOL_OPTIONS.find((option) => option.key === key)

  return matchedOption ? matchedOption.key : DEFAULT_SETTINGS.modbusProtocolFilter
}

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 normalizeSettings(settings = {}) {
  return {
    genericModbusAutoPollEnabled: !!settings.genericModbusAutoPollEnabled,
    genericModbusMaxPacketLength: normalizeGenericPacketLength(
      settings.genericModbusMaxPacketLength,
      DEFAULT_SETTINGS.genericModbusMaxPacketLength
    ),
    genericModbusPollInterval: clampInteger(
      settings.genericModbusPollInterval,
      STATUS_POLL_MIN_INTERVAL,
      STATUS_POLL_MAX_INTERVAL,
      DEFAULT_SETTINGS.genericModbusPollInterval
    ),
    modbusSlaveAddress: normalizeHexByte(settings.modbusSlaveAddress),
    modbusProtocolFilter: normalizeModbusProtocolFilter(settings.modbusProtocolFilter),
    nightModeEnabled: !!settings.nightModeEnabled,
    nightModeFollowSystem: settings.nightModeFollowSystem !== false,
    statusPollInterval: clampInteger(
      settings.statusPollInterval,
      STATUS_POLL_MIN_INTERVAL,
      STATUS_POLL_MAX_INTERVAL,
      DEFAULT_SETTINGS.statusPollInterval
    ),
    userStatusCount: clampInteger(settings.userStatusCount, 0, 999, DEFAULT_SETTINGS.userStatusCount)
  }
}

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({
    ...DEFAULT_SETTINGS,
    ...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 getModbusSlaveAddress() {
  init()
  return parseHexByte(state.modbusSlaveAddress, 'Modbus从机地址')
}

function setModbusProtocolFilter(value) {
  init()
  setState({
    modbusProtocolFilter: normalizeModbusProtocolFilter(value)
  })
}

function setGenericModbusAutoPollEnabled(value) {
  init()
  setState({
    genericModbusAutoPollEnabled: !!value
  })
}

function setGenericModbusMaxPacketLength(value) {
  init()
  setState({
    genericModbusMaxPacketLength: normalizeGenericPacketLength(value, state.genericModbusMaxPacketLength)
  })
}

function setGenericModbusPollInterval(value) {
  init()
  setState({
    genericModbusPollInterval: value
  })
}

function getModbusProtocolFilter() {
  init()
  return state.modbusProtocolFilter
}

function setStatusPollInterval(value) {
  init()
  setState({
    statusPollInterval: value
  })
}

function setUserStatusCount(value, maxValue = 999) {
  init()
  setState({
    userStatusCount: clampInteger(value, 0, maxValue, state.userStatusCount)
  })
}

module.exports = {
  GENERIC_MODBUS_MIN_PACKET_LENGTH,
  MODBUS_PROTOCOL_OPTIONS,
  STATUS_POLL_MAX_INTERVAL,
  STATUS_POLL_MIN_INTERVAL,
  getModbusProtocolFilter,
  getModbusSlaveAddress,
  getState,
  init,
  setGenericModbusAutoPollEnabled,
  setGenericModbusMaxPacketLength,
  setGenericModbusPollInterval,
  setModbusSlaveAddress,
  setModbusProtocolFilter,
  setNightModeEnabled,
  setNightModeFollowSystem,
  setStatusPollInterval,
  setUserStatusCount,
  subscribe
}
