const {
  formatExportStamp,
  isCancelError,
  loadSelectedFile,
  saveTextFileToChat
} = require('../../repositories/file.js')
const {
  getWxApi,
  pickFields
} = require('../../utils/base-utils.js')
const {
  cloneImportedGroup,
  getRegisterJsonValue
} = require('../../domain/parameter-groups/model.js')
const {
  SOURCE_GROUP_FIELDS,
  SOURCE_REGISTER_FIELDS,
  STRUCT_REGISTER_FIELDS
} = require('../../domain/parameter-groups/constants.js')
const {
  PROTOCOL_MODE,
  isModbusProtocolMode
} = require('../../domain/protocol-mode.js')

const STORAGE_KEY = 'parameter-groups-json'
const JSON_DOCUMENT_TYPE = 'parameter-groups'
const JSON_SCHEMA_VERSION = 2
function toPersistedGroups(groups = []) {
  return groups.map((group) => ({
    layout: group.layout,
    name: group.name,
    ...(group.pollEnabled === false ? { pollEnabled: false } : {}),
    registerType: group.registerType,
    startAddress: group.startAddress,
    quantity: group.quantity,
    registers: group.registers.map((register) => ({
      dataType: register.dataType,
      defaultValue: register.defaultValue,
      conversionFormula: register.conversionFormula,
      isStructField: register.isStructField,
      name: register.name,
      maxValue: register.maxValue,
      minValue: register.minValue,
      textByteLength: register.textByteLength,
      remark: register.remark,
      unit: register.unit,
      value: getRegisterJsonValue(register),
      ...pickFields(register, STRUCT_REGISTER_FIELDS),
      ...pickFields(register, SOURCE_REGISTER_FIELDS)
    })),
    ...pickFields(group, SOURCE_GROUP_FIELDS)
  }))
}

function toJsonData(groups = [], options = {}) {
  const jsonData = {
    groups: toPersistedGroups(groups),
    type: JSON_DOCUMENT_TYPE,
    version: JSON_SCHEMA_VERSION
  }

  if (options.includeExportedAt) {
    jsonData.exportedAt = new Date().toISOString()
  }

  return jsonData
}

function toJsonText(groups = [], options = {}) {
  return JSON.stringify(toJsonData(groups, options), null, 2)
}

function normalizeProtocolMode(protocolMode) {
  return isModbusProtocolMode(protocolMode)
    ? PROTOCOL_MODE.MODBUS_RTU
    : PROTOCOL_MODE.STORAGE_ACCESS
}

function getProtocolStorageKey(protocolMode) {
  return `${STORAGE_KEY}:${normalizeProtocolMode(protocolMode)}`
}

function parseJsonGroups(jsonText) {
  const parsed = typeof jsonText === 'string' ? JSON.parse(jsonText) : jsonText
  const groups = Array.isArray(parsed)
    ? parsed
    : (Array.isArray(parsed && parsed.groups) ? parsed.groups : parsed && parsed.parameterGroups)

  if (parsed && parsed.type && parsed.type !== JSON_DOCUMENT_TYPE) {
    throw new Error('JSON 文件不是参数组配置')
  }

  if (parsed && parsed.version && parsed.version !== JSON_SCHEMA_VERSION) {
    throw new Error('JSON 版本不兼容')
  }

  if (!Array.isArray(groups)) {
    throw new Error('JSON 中没有找到寄存器组数组')
  }

  return groups
}

function readStoredGroups(protocolMode = PROTOCOL_MODE.STORAGE_ACCESS) {
  const wxApi = getWxApi()
  if (typeof wxApi.getStorageSync !== 'function') return []

  try {
    const storageKey = getProtocolStorageKey(protocolMode)
    const jsonText = wxApi.getStorageSync(storageKey)
    if (jsonText) return parseJsonGroups(jsonText).map(cloneImportedGroup)
  } catch (error) {
    return []
  }

  return []
}

function persistGroups(groups = [], protocolMode = PROTOCOL_MODE.STORAGE_ACCESS) {
  const wxApi = getWxApi()
  if (typeof wxApi.setStorageSync !== 'function') return

  try {
    wxApi.setStorageSync(getProtocolStorageKey(protocolMode), toJsonText(groups))
  } catch (error) {}
}

function getShareFileName() {
  return `parameter-groups-${formatExportStamp()}.json`
}

async function loadGroupsFromMessageFile() {
  const file = await loadSelectedFile('auto', {
    encoding: 'utf8',
    extensionMessage: '请选择 .json 寄存器配置文件',
    extensions: ['json'],
    fallbackName: 'parameter-groups.json'
  })

  return parseJsonGroups(file.text).map(cloneImportedGroup)
}

async function saveGroupsToChat(groups = []) {
  if (!groups.length) {
    throw new Error('没有可保存的寄存器组')
  }

  const jsonText = toJsonText(groups, {
    includeExportedAt: true
  })

  const result = await saveTextFileToChat(getShareFileName(), jsonText)

  return {
    count: groups.length,
    ...result
  }
}

module.exports = {
  JSON_DOCUMENT_TYPE,
  JSON_SCHEMA_VERSION,
  STORAGE_KEY,
  isCancelError,
  loadGroupsFromMessageFile,
  parseJsonGroups,
  persistGroups,
  readStoredGroups,
  saveGroupsToChat,
  toJsonData,
  toJsonText
}
