const settingsService = require('../../store/settings-store.js')
const themeService = require('../../store/theme-store.js')
const transport = require('../../transport/ble-core.js')
const manualRtuService = require('../../features/manual-rtu/service.js')
const {
  createPageToast
} = require('../../utils/page-toast.js')
const communicationService = require('../../features/communication/service.js')
const {
  LOG_MODE_OPTIONS,
  STORAGE_ACCESS_AREA_OPTIONS,
  STORAGE_ACCESS_COMMAND_OPTIONS,
  decorateLogs,
  getLogModeToggleText,
  getManualStatePayload,
  getNextLogMode,
  getNextSerialMode,
  getProtocolModeState,
  normalizeStorageAccessState,
  normalizeSerialState
} = require('../../features/communication/view-model.js')

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

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

  onLoad() {
    this.pageToast = createPageToast(this, this.data)
    this.lastSyncedSlaveAddress = ''
    transport.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.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.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 communicationService.sendSerialFrame(this.data)
      if (!result.ok) {
        this.setData({
          serialErrorText: result.errorText || '发送失败'
        })
        return
      }

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

  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(event) {
    const storageAccessCommandIndex = Number(event.currentTarget.dataset.index)
    const nextState = normalizeStorageAccessState(this.data, {
      storageAccessCommandIndex
    })

    this.setData(nextState)
  },

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

    const changed = {
      [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, {
      storageAccessAreaIndex
    })

    this.setData(nextState)
  },

  async sendStorageAccessProtocolFrame() {
    try {
      const command = STORAGE_ACCESS_COMMAND_OPTIONS[Number(this.data.storageAccessCommandIndex) || 0] || STORAGE_ACCESS_COMMAND_OPTIONS[0]
      const result = await communicationService.executeStorageAccessProtocol(this.data)
      if (!result.ok) {
        this.setData({
          storageAccessErrorText: result.errorText || '操作失败'
        })
        return
      }

      if (command.key === 'sync') {
        this.setData({
          storageAccessErrorText: '',
          storageAccessSyncInfoText: result.syncInfoText || this.data.storageAccessSyncInfoText
        })
        if (this.pageToast) {
          const codeInfoAddressText = result.codeInfoAddressText || '0000'
          const codeInfoByteLengthText = result.codeInfoByteLengthText || '0000'
          this.pageToast.show(`同步完成 codeInfo 0x${codeInfoAddressText} / 0x${codeInfoByteLengthText}`)
        }
        return
      }

      if (command.key === 'read') {
        this.setData({
          storageAccessErrorText: '',
          storageAccessPreviewHexText: result.previewHex || ''
        })
        if (this.pageToast) this.pageToast.show(`读取完成 ${(result.bytes || []).length} bytes`)
        return
      }

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