import * as React from 'react'
import * as q from '../../../../backend/src/Model'

import { makeConnectionMessageEvent, rendererEvents, MqttMessage } from '../../../../events'

import { AppState } from '../../reducers'
import TreeNode from './TreeNode'
import { connect } from 'react-redux'

const MovingAverage = require('moving-average')

const timeInterval = 10 * 1000
const average = MovingAverage(timeInterval)

declare var window: any

interface Props {
  autoExpandLimit: number
  didSelectNode?: (node: q.TreeNode) => void
  connectionId?: string
  tree?: q.Tree
}

class Tree extends React.Component<Props, {}> {
  private updateTimer?: any
  private lastUpdate: number = 0
  private perf: number = 0

  constructor(props: any) {
    super(props)
    this.state = { }
  }

  public time(): number {
    const time = performance.now() - this.perf
    this.perf = performance.now()

    return time
  }

  public componentWillReceiveProps(nextProps: Props) {
    if (this.props.tree !== nextProps.tree) {
      if (this.props.tree) {
        this.props.tree.onMerge.unsubscribe(this.throttledTreeUpdate)
      }
      if (nextProps.tree) {
        nextProps.tree.onMerge.subscribe(this.throttledTreeUpdate)
      }
    }
  }

  public throttledTreeUpdate = () => {
    if (this.updateTimer) {
      return
    }

    const expectedRenderTime = average.forecast()
    const updateInterval = Math.max(expectedRenderTime * 7, 300)
    const timeUntilNextUpdate = updateInterval - (performance.now() - this.lastUpdate)

    this.updateTimer = setTimeout(() => {
      window.requestIdleCallback(() => {
        this.lastUpdate = performance.now()
        this.updateTimer && clearTimeout(this.updateTimer)
        this.updateTimer = undefined
        this.setState(this.state)
      }, { timeout: 500 })
    }, Math.max(0, timeUntilNextUpdate))
  }

  public componentWillUnmount() {
    if (this.props.connectionId) {
      const event = makeConnectionMessageEvent(this.props.connectionId)
      rendererEvents.unsubscribeAll(event)
    }
  }

  public render() {
    if (!this.props.tree) {
      return null
    }

    const style: React.CSSProperties = {
      lineHeight: '1.1',
      cursor: 'default',
    }

    return (
      <div style={style}>
        <TreeNode
          animateChages={true}
          isRoot={true}
          treeNode={this.props.tree}
          name="/"
          collapsed={false}
          key="rootNode"
          lastUpdate={this.props.tree.lastUpdate}
          performanceCallback={this.performanceCallback}
        />
      </div>
    )
  }

  private performanceCallback = (ms: number) => {
    average.push(Date.now(), ms)
  }
}

const mapStateToProps = (state: AppState) => {
  return {
    autoExpandLimit: state.settings.autoExpandLimit,
    tree: state.connection.tree,
  }
}

export default connect(mapStateToProps)(Tree)
