import React, {Component} from 'react'
import {connect} from 'react-redux'
import styled from 'styled-components'
import UnstyledTextarea from 'react-textarea-autosize'
import {browserHistory} from 'react-router'
import {FaAngleLeft, FaBell, FaBellSlash} from 'react-icons/lib/fa'
import Linkify from 'react-linkify'
import ProfileImage from 'components/profile_image'
import {create_message, store_messages, update_message_id} from '../actions/messages'
import {mute_user, unmute_user, store_muting_recruiters} from '../actions/mutes'
import {set_current_recipient, store_recruiter_users} from '../actions/users'
import {alert_success} from '../actions/display'
import {color} from '../common/constants'
import moment from '../common/moment'
import store from '../common/store'
import request from '../common/request'
import {with_recipient, read_last_messages} from '../common/messages'
import {array_contains, group_consecutive, exist} from '../common/utilities'
import auto_bind from '../common/auto_bind'
import {get_unread_messages, get_messages} from '../selectors/messages'
import {get_current_recipient} from '../selectors/users'
import {tolerant_equal} from '../selectors/base'

class MessagesStatic extends Component {
  constructor(props) {
    super(props)
    auto_bind(this)
  }

  send_message(draft) {
    this.props.send_message(draft)
    if (this.props.muted) {
      this.props.unmute_user()
    }
  }

  componentDidMount() {
    this.props.fetch_messages()
    .then(() => read_last_messages(this.props.recipient.id))
    this.scroll_bottom()
  }

  componentWillReceiveProps(props) {
    if (props.recipient.id != this.props.recipient.id) {
      this.props.fetch_messages()
    }
    if (!tolerant_equal(props.messages, this.props.messages) && exist(props.messages, (message) => !message.read_at && message.recipient_type == "Agency")) {
      read_last_messages(props.recipient.id)
    }
    this.should_scroll_bottom = this.should_scroll_bottom || props.messages.length !== this.props.messages.length
  }

  scroll_bottom() {
    this.scroll_container.scrollTop = this.scroll_container.scrollHeight
  }

  componentWillUpdate() {
    this.should_scroll_bottom = this.should_scroll_bottom || this.scroll_container.scrollTop + this.scroll_container.offsetHeight === this.scroll_container.scrollHeight
  }

  componentDidUpdate() {
    if (this.should_scroll_bottom) {
      this.scroll_bottom()
      this.should_scroll_bottom = false
    }
  }

  render() {
    return (
      <div style={{justifyContent: 'space-between', alignItems: 'stretch', flexDirection: 'column', display: "flex", height: "100%", flex: 1}}>
        <div style={{height: 50, display: 'flex', flexShrink: 0, borderBottomStyle: 'solid', borderBottomColor: color('black', 'bright'), borderBottomWidth: 1, padding: 5, flexDirection: 'row', alignItems: 'center'}}>
          <div style={{display: 'flex', flex: 1, flexDirection: 'row', alignItems: 'space-between', alignItems: 'center'}}>
            <div className="link" onClick={() => store.dispatch(set_current_recipient())} style={{height: 50, alignItems: "center", display: "flex"}}>
              <FaAngleLeft style={{fontSize: 30}}/>
              {this.props.unread_messages > 0 ? (
                <div>
                  ({this.props.unread_messages})
                </div>
              ) : null}
            </div>
            <div className="link" onClick={() => this.props.set_current_user()} style={{marginLeft: 10}}>
              {this.props.recipient.full_name}
            </div>
          </div>
          {
            // this.props.muted ? (
            //   <div className="link" onClick={() => this.props.unmute_user()}>
            //     <FaBellSlash style={{fontSize: 20, margin: 10, color: color('primary', 'light')}}/>
            //   </div>
            // ) : (this.props.can_mute ? (
            //   <div className="link" onClick={() => this.props.mute_user()}>
            //     <FaBell style={{fontSize: 20, margin: 10, opacity: 0.54}}/>
            //   </div>
            // ) : (
            //   <div style={{cursor: 'not-allowed'}}>
            //     <FaBell style={{fontSize: 20, margin: 10, opacity: 0.38}}/>
            //   </div>
            // ))
          }
        </div>
        <div style={{flexGrow: 10000, flexShrink: 1, overflow: 'scroll'}} ref={(scroll_container) => this.scroll_container = scroll_container}>
          <div style={{display: 'flex', flexDirection: 'column', alignItems: 'stretch'}}>
            <Conversations {...this.props}/>
          </div>
        </div>
        <MessageInput send_message={this.send_message} />
      </div>
    )
  }
}

class MessageInput extends Component {
  constructor(props) {
    super(props)
    this.state = {
      draft: '',
    }
  }

  render() {
    return (
      <div style={{flexGrow: 1, flexShrink: 0, bottom: 0, minHeight: 40, backgroundColor: color('black', 'bright'), padding: 3}}>
        <Textarea
          placeholder="Message"
          value={this.state.draft}
          onChange={(event) => {
            let draft = event.target.value
            if (draft.slice(0, -1) != this.state.draft) {
              this.setState({draft})
            } else {
              if (draft.slice(-1) === '\n') {
                this.props.send_message(this.state.draft)
                this.setState({draft: ''})
              } else {
                this.setState({draft})
              }
            }
          }}
          onFocus={(event) => {
            event.target.select()
          }}
          style={{borderStyle: 'none', paddingHeight: 2}}
          />
      </div>
    )
  }
}

const conversation_gap = {unit: 'hours', value: 1}

const Conversations = (props) => {
  let conversations = group_consecutive(props.messages, (m1, m2) => {
    return moment(m2.created_at).diff(moment(m1.created_at), conversation_gap.unit) < conversation_gap.value
  })
  return (
    <div style={{display: 'flex', flexDirection: 'column', alignItems: 'stretch'}}>
      {conversations.map((conversation, index) => <Conversation messages={conversation} key={index} recruiter={props.recruiter} recipient={props.recipient}/>)}
    </div>
  )
}

class Conversation extends Component {
  componentDidMount() {
    read_last_messages(this.props.recipient.id)
  }

  shouldComponentUpdate({recruiter, recipient, messages}) {
    return recipient !== this.props.recipient ||
      recruiter !== this.props.recruiter ||
      !tolerant_equal(messages, this.props.messages)
  }

  render () {
    let message_groups = group_consecutive(this.props.messages, (m1, m2) => {
      return (m1.sender_id == m2.sender_id) && (m1.sender_type == m2.sender_type)
    })

    return (
      <div style={{display: 'flex', flexDirection: 'column', alignItems: 'stretch'}}>
      <span style={{marginRight: 0, flex: 1, textAlign: 'center', color: color('black', 'bright')}}>
        {moment(this.props.messages[this.props.messages.length - 1].created_at).calendar()}
      </span>
        {message_groups.map((group, index) => <MessageGroup messages={group} key={index} recruiter={this.props.recruiter}/>)}
      </div>
    )
  }
}

const MessageGroup = (props) => {
  let group_length = props.messages.length - 1
  let from_user = props.messages[0].sender_type === 'User'

  return (
    <div style={{display: 'flex', flexDirection: 'column', alignItems: 'stretch', paddingTop: 10, paddingBottom: 10}}>
      <div style={{display: 'flex', flexDirection: 'row', alignItems: 'flex-end'}}>
        <div style={Object.assign({display: 'flex', flexDirection: 'column', alignItems: 'stretch'}, !from_user ? {marginLeft: 'auto'} : {})}>
          {props.messages.map((message, index) => <Message message={message} key={message.id} recruiter={props.recruiter} first={index == 0} last={index == group_length}/>)}
        </div>
        {from_user ? null : (
          <ProfileImage {...props.messages[0].sender} hide_status />
        )}
      </div>
        {props.messages[group_length].last_read_message ? (
          <p style={{marginRight: 0, flex: 1, textAlign: 'right', color: color('black', 'bright')}}>Lu {moment(props.messages[group_length].read_at).fromNow()}</p>
        ) : (props.messages[group_length].last_message ? (
          <p style={{marginRight: 0, flex: 1, textAlign: 'right', color: color('black', 'bright')}}>Envoyé {moment(props.messages[group_length].created_at).fromNow()}</p>
        ) : null)}
    </div>
  )
}

const border_normal = 10
const border_small = 3

const Message = (props) => {
  let from_user = props.message.sender_type === 'User'
  let from_self = props.message.sender_type === 'Recruiter' && props.message.sender_id === props.recruiter

  return (
    <div>
      <div style={Object.assign({
        display: "flex",
        flexDirection: 'column',
      }, !from_user ? {
        marginRight: 5,
        float: 'right',
        alignItems: 'flex-end',
      } : {
        marginLeft: 5,
        float: 'left',
        alignItems: 'flex-start',
      }, props.message.last_read_message ? {} : {
        marginBottom: 2,
      })}>
        <div style={Object.assign({
          padding: 10,
          maxWidth: 200,
          borderRadius: border_normal,
          wordWrap: "break-word",
        }, from_self ? {
          backgroundColor: color('primary', 'light'),
          color: 'white',
        } : {
          backgroundColor: '#DDD',
          color: 'black',
        }, !from_user ? {
          borderTopRightRadius: props.first ? border_normal : border_small,
          borderBottomRightRadius: props.last ?  border_normal : border_small,
        } : {
          borderTopLeftRadius: props.first ?  border_normal : border_small,
          borderBottomLeftRadius: props.last ?  border_normal : border_small,
        }
         )}>
          <Linkify properties={{className: 'link', style: {color: color('white'), textDecoration: 'underline'}}}>{props.message.content}</Linkify>
        </div>
      </div>
    </div>
  )
}

const Messages = connect(
  (state) => {
    let messages = get_messages(state)
    .filter((message) => with_recipient(message, state.users.current_recipient))
    .sort((m1, m2) => moment(m1.created_at).isAfter(m2.created_at) ? 1 : -1)

    let i = messages.length - 1
    let last_message = messages[i]
    messages[i] = {...last_message, last_message: true}
    while (i >= 0 && (messages[i].sender_type === 'User' || messages[i].read_at == null)) {
      i--
    }
    if (i >= 0) {
      messages[i] = {...messages[i], last_read_message: true, last_message: false}
    }
    return {
      messages,
      recipient: get_current_recipient(state),
      recruiter: state.profile.id,
      muted: array_contains(state.mutes.muted_users, state.users.current_recipient),
      can_mute: messages.reduce((can_mute, message) =>
        can_mute || (
          message.sender_type === 'Recruiter' &&
          message.sender_id != state.profile.id &&
          !array_contains(state.mutes.mutes_by_user[state.users.current_recipient], message.sender_id)
        ),
        false
      ) && messages.filter((message) => message.sender_type === 'Recruiter').length > 0,
      unread_messages: get_unread_messages(state)
    }
  },
  (dispatch) => {
    let toggle_mute_user = (mute) => {
      let state = store.getState()
      let user = get_current_recipient(state)
      let action, triggered_action, alert_text
      if (mute) {
        action = unmute_user
        triggered_action = 'mutes.unmute'
        alert_text = `Vous recevrez à nouveau les alertes pour les nouveaux messages de ${user.full_name}`
      } else {
        action = mute_user
        triggered_action = 'mutes.mute'
        alert_text = `Vous ne recevrez plus d'alertes pour les nouveaux messages de ${user.full_name}`
      }
      dispatch(action(user.id))
      dispatch(alert_success(alert_text))
    }
    return {
      send_message: (content) => {
        let state = store.getState()
        let user_id = state.users.current_recipient
        let temp_id = state.messages.idGenerator
        let message = {
          id: temp_id,
          content,
          sender_id: state.profile.id,
          sender_type: "Recruiter",
          recipient_id: user_id,
          recipient_type: "User",
        }
        dispatch(create_message(message))
        request.post('messages', {message: {content}, user_id})
        .then((message) => dispatch(update_message_id(message, temp_id)))
      },
      fetch_messages: () => {
        let state = store.getState()
        request.get(`users/${state.users.current_recipient}/muting_recruiters`)
        .then((recruiters) => dispatch(store_muting_recruiters(state.users.current_recipient, recruiters.map((recruiter) => recruiter.id))))
        return request.get('messages', {user_id: state.users.current_recipient})
        .then((messages) => dispatch(store_messages(messages)))
      },
      set_current_user: () => {
        browserHistory.push(`/users/${store.getState().users.current_recipient}`)
      },
      mute_user: () => toggle_mute_user(false),
      unmute_user: () => toggle_mute_user(true),
    }
  }
)(MessagesStatic)

export default Messages

const Textarea = styled(UnstyledTextarea)`
  font-size: 14px;
  padding: 10px 15px;
  width: 85%;
  margin: 2px;
  border-radius: 5px;
`
