import _ from 'lodash'
import React, { Component } from 'react'
import { Provider } from 'react-redux'
import { DevInfo, DpValue, Theme, TYSdk } from 'tuya-panel-kit'
import { actions, store } from './models'
import {addListener, nativeEventEmitter, removeListener} from 'api/nativeEventEmitter'
import {getSystemTimeFormat, getTimeZone, NativeApi} from 'api/native'
import {
  DeviceInfo,
  NativeProps,
  setGroupDevices,
  setGroupNativeProps,
  setNativeProps,
  setSystemTimeFormat,
  setTimeZone,
  UAGroupInfo,
} from './models/modules/NativePropsSlice'
import { DpSchema, GlobalParams } from './models/GlobalParams'
import Connect from './components/connect'
import darkTheme from "./config/dark-theme";
import lightTheme from "./config/light-theme";

interface Props {
  devInfo: DevInfo
  preload?: boolean
  ldvDevInfo: LdvDevInfo
  uaGroupInfo: UAGroupInfoProps
  colorScheme?: string
}

interface LdvDevInfo extends DeviceInfo {
  schema: any
  familyName: string
  role: 0 | 1 | 2 | 3
}

interface UAGroupInfoProps extends UAGroupInfo {
  schema: any
  familyName: string
  role: 0 | 1 | 2 | 3
}

const TYEvent = TYSdk.event
const TYDevice = TYSdk.device

/**
 *
 * @param {} component - 需要连接到redux store的组件，通常为即为main
 */
const composeLayout = (component: React.ComponentType) => {
  const NavigatorLayout = component
  const { dispatch } = store

  addListener(store)

  /**
   * 此处监听了`设备数据变更`事件，
   * 每当dp点数据变更时，会将变更的dp点状态同步更新到`redux`中去。
   * 同理当设备信息变更时，也会将变更的设备信息值同步更新到`redux`中去。
   */
  TYEvent.on('deviceDataChange', data => {
    switch (data.type) {
      case 'dpData':
        dispatch(actions.common.responseUpdateDp(data.payload as Record<string, DpValue>))
        break
      case 'deviceOnline':
        console.log('设备在线状态', data.payload)
        break
      default:
        dispatch(actions.common.deviceChange(data.payload as DevInfo))
        break
    }
  })

  /**
   * 此处监听了`网络状态变更事件`事件，
   * 每当设备信息变更时，会将变更的设备信息值同步更新到`redux`中去。
   */
  TYSdk.event.on('networkStateChange', data => {
    dispatch(actions.common.deviceChange(data as any))
  })

  class PanelComponent extends Component<Props> {
    /**
     * 如果面板进入时，`devInfo`已经存在(通常都会存在的)
     * 这里会调用 setDeviceInfo 将原始的devInfo处理一下，并置入`redux`
     *
     * 如果面板进入时，`devInfo`不存在，
     * 那么会调用 getDeviceInfo 异步获取处理好的`devInfo`，并置入`redux`
     */
    state = {
      colorScheme: 'light'
    }
    constructor(props: Props) {
      super(props)
      if (props && props.devInfo && props.devInfo.devId) {
        TYDevice.setDeviceInfo(props.devInfo)
        TYDevice.getDeviceInfo()
          .then(data => {
            dispatch(actions.common.devInfoChange(data))
            return Promise.all([TYDevice.getDeviceState(), data])
          })
          .then(([dpState, devInfo]) => {
            const isEqual = _.isEqual(dpState, devInfo.state)
            if (isEqual) return
            dispatch(actions.common.responseUpdateDp(dpState))
          })
      } else if (props.preload) {
        // do something
      } else {
        TYDevice.getDeviceInfo().then(data => dispatch(actions.common.devInfoChange(data)))
      }

      if (!!props.ldvDevInfo) {
        this.initReduxDeviceNativeProps(props.ldvDevInfo)
      } else {
        this.initReduxGroupNativeProps(props.uaGroupInfo)
        this.initGroupDevices(props.uaGroupInfo?.tyGroupId)
      }

      if (!!props.colorScheme) {
        this.state = {
          colorScheme: props.colorScheme || 'light'
        }
      }
      getSystemTimeFormat().then(time => {
        dispatch(setSystemTimeFormat(time === 24))
      })

      getTimeZone().then(timeZone => {
        dispatch(setTimeZone(timeZone))
      })
    }

    initReduxDeviceNativeProps(ldvDevInfo: LdvDevInfo) {
      console.log('原生数据：', JSON.stringify(ldvDevInfo))
      NativeApi.log('原生数据: ' + JSON.stringify(ldvDevInfo))
      const dps = this.setDpSchemaMap(ldvDevInfo.schema)
      const nativeProps: NativeProps = {
        deviceInfo: {
          devId: ldvDevInfo.devId,
          dps: { ...dps, ...JSON.parse(ldvDevInfo.dps) },
          pId: ldvDevInfo.pId,
        },
        uaGroupInfo: {
          tyGroupId: -1,
          dps: {},
          pId: '',
          config: {},
          groupDevices: []
        },
        familyName: ldvDevInfo.familyName,
        role: ldvDevInfo.role,
        moods: [],
        is24HourClock: true
      }
      NativeApi.showObj(nativeProps)
      console.log('Redux 初始数据：', JSON.stringify(nativeProps))
      NativeApi.log('Redux 初始数据：' + JSON.stringify(nativeProps))
      dispatch(setNativeProps(nativeProps))
    }

    initReduxGroupNativeProps(uaGroupInfo: UAGroupInfoProps) {
      console.log('原生数据：', JSON.stringify(uaGroupInfo))
      NativeApi.log('原生数据: ' + JSON.stringify(uaGroupInfo))
      const dps = this.setDpSchemaMap(uaGroupInfo.schema)
      const nativeProps: NativeProps = {
        deviceInfo: {
          devId: '',
          dps: {},
          pId: '',
        },
        uaGroupInfo: {
          tyGroupId: uaGroupInfo.tyGroupId,
          dps: { ...dps, ...JSON.parse(uaGroupInfo.dps) },
          pId: uaGroupInfo.pId,
          config: {
            ...JSON.parse(uaGroupInfo.config || '{}'),
          },
          name: uaGroupInfo.name,
          groupDevices: [],
          icon: !!uaGroupInfo.icon ? uaGroupInfo.icon : undefined,
          deviceIds: uaGroupInfo.deviceIds
        },
        familyName: uaGroupInfo.familyName,
        role: uaGroupInfo.role,
        moods: [],
        is24HourClock: true
      }
      NativeApi.showObj(nativeProps)
      console.log('Redux 初始数据：', JSON.stringify(nativeProps))
      NativeApi.log('Redux 初始数据：' + JSON.stringify(nativeProps))
      dispatch(setGroupNativeProps(nativeProps))
    }

    async initGroupDevices(tyGroupId: number){
      if(!tyGroupId) return
      const res = await NativeApi.getGroupDevices(tyGroupId)
      if(res.success && Array.isArray(res.data)){
        dispatch(setGroupDevices(res.data))
      }
    }

    setDpSchemaMap(schema: string): any {
      // 处理物模型协议和dps
      const dpSchemaMap: Record<string, DpSchema> = {}
      const dps = {}
      JSON.parse(schema || '[]')
        .forEach((schemaItem: any) => {
          dpSchemaMap[schemaItem.code] = {
            name: schemaItem.name,
            dp: schemaItem.id,
            type: schemaItem.type,
            mode: schemaItem.mode,
            property: schemaItem.property,
          }
          dps[schemaItem.id] = null
        })
      GlobalParams.dpSchemaMap = dpSchemaMap
      return dps
    }

    componentDidMount() {
      nativeEventEmitter.addListener('ColorSchemeUpdate', this.handleColorSchemeUpdate)
    }

    componentWillUnmount() {
      removeListener()
      nativeEventEmitter.removeListener('ColorSchemeUpdate', this.handleColorSchemeUpdate)
    }

    handleColorSchemeUpdate = (event: { colorScheme: string }) => {
      this.updateColorScheme(event.colorScheme)
    }

    updateColorScheme(colorScheme: string) {
      this.setState({
        colorScheme: colorScheme
      })
    }

    render() {
      const { colorScheme } = this.state
      // const colorScheme = 'light'
      return (
        <Provider store={store}>
          <Theme theme={colorScheme === 'dark' ? darkTheme : lightTheme}>
            <Connect mapStateToProps={_.identity}>
              {({ mapStateToProps, ...props }: { mapStateToProps: any; [_: string]: any }) => {
                return <NavigatorLayout {...props} />
              }}
            </Connect>
          </Theme>
        </Provider>
      )
    }
  }

  return PanelComponent
}


export default composeLayout
