import React from 'react'
import styles from './styles.css'
import MessagingButton from './components/MessagingButton'
import MessagingPopup from './components/MessagingPopup'
import MesesMessagingApp from '../app'

class MesesMessagingUI extends React.Component {
  constructor() {
    super()
    this.CLASS_TAG = '[MESES_MESSAGING_UI]'
  }

  componentWillMount() {
    this.setState({
      buttonVisible: false, 
      popupVisible: false, 
      messageListVisible: false,
      conversationList: [],
      messageList: [],
      messageBuffer: [],
      hasMoreMessage: true,
      totalUnreadCount: 0,
      lastConversationScrollTop: 0
    })
    
    let { targetUri, applicationId, username } = this.props
    this._app = new MesesMessagingApp(targetUri, applicationId)
    this._handleConnect(username)
  }

  handleMessagingButtonOnClick() {
    let { popupVisible, conversationList } = this.state

    this.setState({ popupVisible: !popupVisible })
  }

  handleConversationEntryOnClick(conversationName, scrollTop) { 
    this._handlePrepareConversation(conversationName, scrollTop) 
  }

  handleBackButtonOnClick() {
    this.setState({ messageList: [], messageBuffer: [], messageListVisible: false })
    this._app.detachUpdateHandler(this.activeConversation.conversationName)
    this.activeConversation = null;
  }

  handleSendButtonOnClick(message) {
    message = message.trim()
    if (message.length > 0) this._handleSendMessageAction(message)
  }

  render() {
    let { buttonIcon, buttonClass, popupClass } = this.props
    let { buttonVisible, popupVisible, messageListVisible } = this.state
    let { hasMoreMessage, hasMoreConversation, lastConversationScrollTop } = this.state
    let { conversationList, messageList, messageBuffer } = this.state
    let { activeTitle, connectedUser, totalUnreadCount } = this.state

    let messagingPopup = popupVisible ?
      <MessagingPopup
        className={ popupClass }
        conversationList={ conversationList }
        messageList={ messageList }
        messageBuffer={ messageBuffer }
        messageListVisible={ messageListVisible }
        hasMoreConversation={ hasMoreConversation }
        hasMoreMessage={ hasMoreMessage }
        title={ activeTitle } connectedUser={ connectedUser }
        lastConversationScrollTop={ lastConversationScrollTop }
        conversationEntryOnClick={ this.handleConversationEntryOnClick.bind(this) }
        backButtonOnClick={ this.handleBackButtonOnClick.bind(this) }
        sendButtonOnClick={ this.handleSendButtonOnClick.bind(this) }
        loadMoreConversation={ this._handleLoadConversation.bind(this) }
        loadMoreMessage={ this._handleLoadMessage.bind(this) }
      /> : ''

    let messagingButton = buttonVisible ?
      <MessagingButton 
        className={ buttonClass }
        buttonIcon={ buttonIcon } 
        totalUnreadCount={ !popupVisible ? totalUnreadCount : 0 }
        onClick= { this.handleMessagingButtonOnClick.bind(this) } 
      /> : ''

    return (
      <div className={ styles.base }>
        { messagingPopup }
        { messagingButton }
      </div>
    )
  }

  _handleConnect(username) {
    this._app.connect(username)
      .then(function(result) { 
        this.prevConvListQuery = this._app.createPreviousConversationListQuery()
        this.setState({ connectedUser: result, buttonVisible: true })
        this.activeConversation = null
        this._handleLoadConversation()
        this._handleConversationUpdate()
      }.bind(this))
      .catch(err => console.error(this.CLASS_TAG, err))
  }

  _handleLoadConversation() {
    let { fetchConversationSize } = this.props
    let { conversationList, totalUnreadCount } = this.state

    this.prevConvListQuery.load(fetchConversationSize ? fetchConversationSize : 10)
      .then(function(result) {
        let tmpCount = result.map(x => x.unreadCount).reduce((sum, value) => sum + value)
        this.setState({ 
          conversationList: conversationList.concat(result),
          totalUnreadCount: totalUnreadCount + tmpCount,
          hasMoreConversation: this.prevConvListQuery.hasMore()
        })
      }.bind(this))
      .catch(err => console.error(this.CLASS_TAG, err))
  }

  _handleLoadMessage() {
    let { fetchMessageSize } = this.props
    let { messageList } = this.state

    this.prevMsgListQuery.load(fetchMessageSize ? fetchMessageSize : 20)
      .then(function(result) {
        result.reverse()
        this.setState({ 
          messageList: result.concat(messageList), 
          messageListVisible: true,
          hasMoreMessage: this.prevMsgListQuery.hasMore()
        })
      }.bind(this))
      .catch(err => console.error(this.CLASS_TAG, err))
  }

  _handlePrepareConversation(conversationName, scrollTop) {
    this._app.getConversation(conversationName)
      .then(function(conversation) {
        this.activeConversation = conversation
        this.prevMsgListQuery = conversation.createPreviousMessageListQuery()
        this.setState({ 
          messageListVisible: true, 
          activeTitle: conversation.title ? conversation.title : conversation.conversationName,
          lastConversationScrollTop: scrollTop
        })
        this._handleMessageUpdate()
        this._handleMarkAsRead(conversationName)
        this._handleLoadMessage()
      }.bind(this))
      .catch(err => console.error(this.CLASS_TAG, err))
  }

  _handleMarkAsRead(conversationName) {
    let { conversationList, totalUnreadCount } = this.state
    
    let conversation = conversationList.find(c => c.conversationName === conversationName)
    const count = conversation.unreadCount; conversation.unreadCount = 0;
    this.setState({ conversationList: conversationList, totalUnreadCount: totalUnreadCount - count })
    this.activeConversation.markAsRead()
  }

  _handleSendMessageAction(message) {
    let { connectedUser, messageBuffer } = this.state

    this.activeConversation.sendMessage(message, { displayName: connectedUser.displayName })
      .then(function(message) {
        messageBuffer.push(message)
        this.setState({ messageBuffer: messageBuffer })
        this.activeConversation.markAsRead()
      }.bind(this))
      .catch(err => console.error(this.CLASS_TAG, err))
  }

  _handleConversationUpdate() {
    let { refreshRate } = this.props

    if (refreshRate) {
      let handler = this._app.createConversationUpdateHandler(
        'conv-update-handler', 
        this._conversationUpdateCallback.bind(this),
        refreshRate
      )
      this._app.attachUpdateHandler(handler)
    }
  }

  _handleMessageUpdate() {
    let { refreshRate } = this.props

    if (refreshRate) {
      let handler = this.activeConversation.createNewMessageUpdateHandler(
        this.activeConversation.conversationName,
        this._newMessageUpdateCallback.bind(this),
        refreshRate
      )
      this._app.attachUpdateHandler(handler)
    }
  }

  _conversationUpdateCallback(err, result) {
    let { conversationList, totalUnreadCount } = this.state
    let tmpUnreadCount = 0
    
    if (err) console.error(this.CLASS_TAG, err)
    else if (result.updatedConversationPayloads.length > 0) {
      result.updatedConversationPayloads.map(x => {
        let found = conversationList.find(c => c.conversationName === x.conversationName)
        if (found) {
          tmpUnreadCount -= found.unreadCount
          found.lastMessageText = x.lastMessageText
          found.lastMessageTime = x.lastMessageTime
          if (this.activeConversation == null || this.activeConversation.conversationName != x.conversationName)
            found.unreadCount = x.unreadCount
        } else {
          conversationList.push(x)
        }
        tmpUnreadCount += x.unreadCount
      })
      conversationList.sort((a, b) => b.lastMessageTime - a.lastMessageTime)
      this.setState({ conversationList: conversationList, totalUnreadCount: totalUnreadCount + tmpUnreadCount })
    }
  }

  _newMessageUpdateCallback(err, result) {
    let { messageList, messageBuffer } = this.state

    if (err) console.error(this.CLASS_TAG, err)
    else if (result.messages.length > 0) {
      result.messages.reverse()
      result.messages.map(x => {
        let idx = messageBuffer.findIndex(message => message.messageId === x.messageId)
        if (idx != -1) messageBuffer.splice(idx, 1)
        messageList.push(x)
      })
      this.setState({ messageList: messageList, messageBuffer: messageBuffer })
    }
  }

}

export default MesesMessagingUI