const settingsService = require('../../store/settings-store.js')
const themeService = require('../../store/theme-store.js')
const transport = require('../../transport/ble-core.js')
const {
  createPageToast
} = require('../../utils/page-toast.js')
const {
  parameterGroupService
} = require('../../features/parameter-groups/index.js')
const {
  LOG_MODE_OPTIONS,
  decorateLogs,
  executeStorageAccessProtocol,
  executeStorageAccessSpecialCommand,
  getLogModeToggleText,
  getManualStatePayload,
  getNextLogMode,
  getNextSerialMode,
  getProtocolModeState,
  getStorageAccessAreaOptions,
  manualRtuService,
  sendSerialFrame,
  normalizeStorageAccessSpecialState,
  normalizeStorageAccessState,
  normalizeSerialState
} = require('../../features/communication/index.js')

const INITIAL_SERIAL_STATE = normalizeSerialState({
  serialInputText: '',
  serialMode: 'hex'
})

Page({
  data: {
    ...themeService.getState(),
    ...settingsService.getState(),
    ...getProtocolModeState(settingsService.getState()),
    ...transport.getState(),
    ...parameterGroupService.getState(),
    ...manualRtuService.getState(),
    logs: decorateLogs(transport.getState().logs, 'hex'),
    logMode: 'hex',
    logModeToggleText: getLogModeToggleText('hex'),
    logModeOptions: LOG_MODE_OPTIONS,
    storageAccessAreaOptions: getStorageAccessAreaOptions(),
    ...normalizeStorageAccessState({
      storageAccessAreaIndex: 0,
      storageAccessAddress: '',
      storageAccessCommandIndex: 0,
      storageAccessDataText: '',
      storageAccessLength: ''
    }),
    ...normalizeStorageAccessSpecialState(),
    serialTitleText: '串口发送',
    ...INITIAL_SERIAL_STATE,
    toastText: '',
    toastType: ''
  },

  onLoad() {
    this.pageToast = createPageToast(this, this.data)
    this.lastSyncedSlaveAddress = ''
    transport.init()
    parameterGroupService.init()
    settingsService.init()
    themeService.init()

    const settingsState = settingsService.getState()
    manualRtuService.setProtocolInput({
      slaveAddress: settingsState.modbusSlaveAddress
    })
    this.lastSyncedSlaveAddress = settingsState.modbusSlaveAddress

    this.unsubscribeTheme = themeService.subscribe((themeState) => {
      this.setData(themeState)
    })

    this.unsubscribeSettings = settingsService.subscribe((settingsState) => {
      this.setData({
        ...settingsState,
        ...getProtocolModeState(settingsState)
      })

      if (settingsState.modbusSlaveAddress !== this.lastSyncedSlaveAddress) {
        this.lastSyncedSlaveAddress = settingsState.modbusSlaveAddress
        manualRtuService.setProtocolInput({
          slaveAddress: settingsState.modbusSlaveAddress
        })
      }
    })

    this.unsubscribeTransport = transport.subscribe((transportState) => {
      this.setData({
        ...transportState,
        logs: decorateLogs(transportState.logs, this.data.logMode)
      })
    })

    this.unsubscribeParameterGroups = parameterGroupService.subscribe((parameterState) => {
      this.setData({
        ...parameterState,
        ...normalizeStorageAccessState(this.data, {
          storageAccessCommandIndex: this.data.storageAccessCommandIndex,
          storageAccessAreaIndex: this.data.storageAccessAreaIndex
        })
      })
    })

    this.unsubscribeManualRtu = manualRtuService.subscribe((manualState) => {
      this.setData(getManualStatePayload(manualState))
    })
  },

  onShow() {
    if (this.pageToast) {
      this.pageToast.setActive(true)
    }
  },

  onHide() {
    if (this.pageToast) {
      this.pageToast.setActive(false)
    }
  },

  onUnload() {
    if (this.pageToast) {
      this.pageToast.destroy()
      this.pageToast = null
    }

    if (this.unsubscribeTheme) {
      this.unsubscribeTheme()
      this.unsubscribeTheme = null
    }

    if (this.unsubscribeSettings) {
      this.unsubscribeSettings()
      this.unsubscribeSettings = null
    }

    if (this.unsubscribeTransport) {
      this.unsubscribeTransport()
      this.unsubscribeTransport = null
    }

    if (this.unsubscribeParameterGroups) {
      this.unsubscribeParameterGroups()
      this.unsubscribeParameterGroups = null
    }

    if (this.unsubscribeManualRtu) {
      this.unsubscribeManualRtu()
      this.unsubscribeManualRtu = null
    }
  },

  noop() {},

  switchSerialMode() {
    this.setData(normalizeSerialState(this.data, {
      serialMode: getNextSerialMode(this.data.serialMode)
    }))
  },

  switchLogMode(event) {
    const requestedMode = event && event.currentTarget && event.currentTarget.dataset
      ? event.currentTarget.dataset.mode
      : ''
    const mode = requestedMode || getNextLogMode(this.data.logMode)
    this.setData({
      logMode: mode,
      logModeToggleText: getLogModeToggleText(mode),
      logs: decorateLogs(transport.getState().logs, mode)
    })
  },

  clearCommunicationLogs() {
    transport.clearLogs()
  },

  onSerialInput(event) {
    this.setData(normalizeSerialState(this.data, {
      serialInputText: event.detail.value
    }))
  },

  clearSerialInput() {
    this.setData(normalizeSerialState(this.data, {
      serialInputText: ''
    }))
  },

  async sendSerialFrame() {
    try {
      const result = await sendSerialFrame(this.data)
      if (!result.ok) {
        if (this.pageToast) this.pageToast.show(result.errorText || '发送失败', 'error')
        return
      }

      if (this.pageToast) this.pageToast.show('已发送')
      this.setData({
        ...(result.serialState || {}),
        serialPreviewHex: result.previewHex || '',
        serialPreviewLengthText: `${(result.bytes || []).length} bytes`
      })
    } catch (error) {
      if (this.pageToast) this.pageToast.show(error.message || '发送失败', 'error')
    }
  },

  onProtocolCommandChange(event) {
    manualRtuService.setCommandIndex(Number(event.detail.value))
  },

  onProtocolInput(event) {
    const field = event.currentTarget.dataset.field
    if (!field) return

    manualRtuService.setProtocolInput({
      [field]: event.detail.value
    })
  },

  onProtocolCoilChange(event) {
    manualRtuService.setProtocolInput({
      coilEnabled: !!event.detail.value
    })
  },

  openProtocolMultipleDialog() {
    manualRtuService.openProtocolMultipleDialog()
  },

  closeProtocolMultipleDialog() {
    manualRtuService.closeProtocolMultipleDialog()
  },

  toggleProtocolMultipleExpanded() {
    manualRtuService.toggleProtocolMultipleExpanded()
  },

  onProtocolMultipleQuantityChange(event) {
    manualRtuService.setProtocolMultipleQuantity(event.detail.value)
  },

  onProtocolMultipleValueInput(event) {
    const index = Number(event.currentTarget.dataset.index)
    manualRtuService.setProtocolMultipleValue(index, event.detail.value)
  },

  onProtocolMultipleTypeChange(event) {
    const index = Number(event.currentTarget.dataset.index)
    manualRtuService.setProtocolMultipleType(index, Number(event.detail.value))
  },

  onProtocolMultipleTextLengthInput(event) {
    const index = Number(event.currentTarget.dataset.index)
    manualRtuService.setProtocolMultipleTextLength(index, event.detail.value)
  },

  async sendProtocolFrame(event) {
    const source = event && event.currentTarget && event.currentTarget.dataset
      ? event.currentTarget.dataset.source
      : ''

    if (this.data.protocolMultipleDialog && this.data.protocolMultipleDialog.visible && source !== 'dialog') {
      if (this.pageToast) this.pageToast.show('请在多值窗口内发送', 'error')
      return
    }

    if (!this.data.connectedDevice) {
      if (this.pageToast) this.pageToast.show('请先连接蓝牙设备', 'error')
      return
    }

    const response = await manualRtuService.sendGeneratedFrame()
    if (response && this.pageToast) {
      this.pageToast.show(response === true ? '已发送' : '已收到回复')
    } else if (this.pageToast) {
      const manualState = manualRtuService.getState()
      this.pageToast.show(manualState.protocolStatusText || '发送失败或超时未回复', 'error')
    }
  },

  switchStorageAccessCommandMode() {
    const currentIndex = Number(this.data.storageAccessCommandIndex) || 0
    const nextState = normalizeStorageAccessState(this.data, {
      storageAccessCommandIndex: currentIndex === 0 ? 1 : 0
    })

    this.setData(nextState)
  },

  onStorageAccessInput(event) {
    const field = event.currentTarget.dataset.field
    if (!field) return

    const changed = {
      storageAccessCommandIndex: this.data.storageAccessCommandIndex,
      [field]: event.detail.value
    }
    const nextState = normalizeStorageAccessState(this.data, changed)

    this.setData(nextState)
  },

  onStorageAccessAreaChange(event) {
    const storageAccessAreaIndex = Number(event.detail.value)
    const nextState = normalizeStorageAccessState(this.data, {
      storageAccessCommandIndex: this.data.storageAccessCommandIndex,
      storageAccessAreaIndex
    })

    this.setData(nextState)
  },

  async sendStorageAccessProtocolFrame() {
    try {
      if (!this.data.connectedDevice) {
        if (this.pageToast) this.pageToast.show('请先连接蓝牙设备', 'error')
        return
      }

      const result = await executeStorageAccessProtocol(this.data)
      if (!result.ok) {
        if (this.pageToast) this.pageToast.show(result.errorText || '操作失败', 'error')
        return
      }

      if (!this.data.storageAccessShowWriteData) {
        this.setData({
          storageAccessPreviewHexText: result.previewHex || ''
        })
        if (this.pageToast) this.pageToast.show(`读取完成 ${(result.bytes || []).length} bytes`)
        return
      }

      if (this.pageToast) this.pageToast.show('写入完成')
    } catch (error) {
      if (this.pageToast) this.pageToast.show(error.message || '操作失败', 'error')
    }
  },

  async syncStorageAccessCodeInfo() {
    if (!this.data.isStorageAccessProtocol) return
    if (!this.data.connectedDevice) {
      if (this.pageToast) this.pageToast.show('请先连接蓝牙设备', 'error')
      return
    }

    const result = await parameterGroupService.syncFromStorageAccessCodeInfo({
      maxPacketLength: this.data.parameterMaxPacketLength
    })
    if (result && result.ok && this.pageToast) {
      this.setData(normalizeStorageAccessState(this.data, {
        storageAccessCommandIndex: this.data.storageAccessCommandIndex,
        storageAccessAreaIndex: 0
      }))
      const codeInfoAddressText = result.codeInfoAddressText || Number(result.codeInfoAddress || 0).toString(16).toUpperCase()
      const codeInfoByteLengthText = result.codeInfoByteLengthText || Number(result.codeInfoByteLength || 0).toString(16).toUpperCase()
      const addedCount = Number(result.addedGroups || 0) + Number(result.addedRegisters || 0)
      const updatedCount = Number(result.updatedGroups || 0) + Number(result.updatedRegisters || 0)
      const changedText = [
        addedCount ? `新增 ${addedCount}` : '',
        updatedCount ? `更新 ${updatedCount}` : ''
      ].filter(Boolean).join('，')

      this.pageToast.show(`同步完成 codeInfo 0x${codeInfoAddressText} / 0x${codeInfoByteLengthText}，${result.structCount} 项${changedText ? `，${changedText}` : ''}`)
    }
  },

  async sendStorageAccessSpecialCommand(event) {
    const commandKey = event && event.currentTarget && event.currentTarget.dataset
      ? event.currentTarget.dataset.command
      : ''
    const command = (this.data.storageAccessSpecialCommands || []).find((item) => item.key === commandKey)

    try {
      const result = await executeStorageAccessSpecialCommand(command, this.data)
      if (!result.ok) {
        if (this.pageToast) this.pageToast.show(result.errorText || '指令执行失败', 'error')
        return
      }

      if (this.pageToast) this.pageToast.show(`${command.label || '特殊指令'}已执行`)
    } catch (error) {
      if (this.pageToast) this.pageToast.show(error.message || '指令执行失败', 'error')
    }
  }
})
