import React from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import ImmutablePropTypes from 'react-immutable-proptypes'
import ImmutablePureComponent from 'react-immutable-pure-component'
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'
import escapeTextContentForBrowser from 'escape-html'
import spring from 'react-motion/lib/spring'
import { me } from '../initial_state'
import Motion from '../features/ui/util/reduced_motion'
import { vote } from '../actions/polls'
import { CX } from '../constants'
import emojify from './emoji/emoji'
import RelativeTimestamp from './relative_timestamp'
import Button from './button'
import DotTextSeperator from './dot_text_seperator'
import Text from './text'

const makeEmojiMap = record => record.get('emojis').reduce((obj, emoji) => {
  obj[`:${emoji.get('shortcode')}:`] = emoji.toJS()
  return obj
}, {})

class Poll extends ImmutablePureComponent {

  state = {
    selected: {},
  }

  handleOptionChange = e => {
    const { target: { value } } = e

    if (this.props.poll.get('multiple')) {
      const tmp = { ...this.state.selected }
      if (tmp[value]) {
        delete tmp[value]
      } else {
        tmp[value] = true
      }
      this.setState({ selected: tmp })
    } else {
      const tmp = {}
      tmp[value] = true
      this.setState({ selected: tmp })
    }
  }

  handleVote = () => {
    if (this.props.disabled) return

    this.props.dispatch(vote(this.props.poll.get('id'), Object.keys(this.state.selected)))
  }

  renderOption(option, optionIndex) {
    const { poll, disabled } = this.props
    const { selected } = this.state
    const percent = poll.get('votes_count') === 0 ? 0 : (option.get('votes_count') / poll.get('votes_count')) * 100
    const leading = poll.get('options').filterNot(other => other.get('title') === option.get('title')).every(other => option.get('votes_count') > other.get('votes_count'))
    const optionHasNoVotes = option.get('votes_count') === 0
    const active = !!selected[`${optionIndex}`]
    const showResults = poll.get('voted') || poll.get('expired')
    const multiple = poll.get('multiple')
    const correctedWidthPercent = optionHasNoVotes ? 100 : percent

    let titleEmojified = option.get('title_emojified')
    if (!titleEmojified) {
      const emojiMap = makeEmojiMap(poll)
      titleEmojified = emojify(escapeTextContentForBrowser(option.get('title')), emojiMap)
    }

    const chartClasses = CX({
      d: 1,
      posAbs: 1,
      top0: 1,
      left0: 1,
      circle: 1,
      h100PC: 1,
      bgSecondary: !leading && !optionHasNoVotes,
      bgBrandLight: leading,
    })

    // : todo :
    const inputClasses = CX('poll__input', {
      'poll__input--checkbox': multiple,
      'poll__input--active': active,
    })

    const listItemClasses = CX({
      d: 1,
      flexRow: 1,
      py10: showResults,
      mb10: 1,
      border1PX: !showResults || !!me,
      borderColorSecondary: !showResults || !!me,
      circle: !showResults || !!me,
      overflowHidden: !!me,
      cursorPointer: !showResults,
      bgSubtle_onHover: !showResults,
      bgSubtle: !showResults && active,
    })

    const textContainerClasses = CX({
      d: 1,
      w100PC: 1,
      px15: 1,
      py10: !showResults,
      cursorPointer: !showResults,
      aiCenter: !showResults,
    })

    // : todo : fix widths and truncate for large poll options
    return (
      <li className={listItemClasses} key={option.get('title')}>
        {
          showResults && (
            <Motion defaultStyle={{ width: 0 }} style={{ width: spring(correctedWidthPercent, { stiffness: 180, damping: 24 }) }}>
              {({ width }) =>
                <span className={chartClasses} style={{ width: `${width}%` }} />
              }
            </Motion>
          )
        }

        <label className={textContainerClasses}>
          <Text
            size='medium'
            color='primary'
            weight={(leading && showResults) ? 'bold' : 'normal'}
            className={[_s.displayFlex, _s.flexRow, _s.w100PC, _s.aiCenter].join(' ')}
          >
            {
              !showResults &&
              <input
                name='vote-options'
                type={multiple ? 'checkbox' : 'radio'}
                value={optionIndex}
                checked={active}
                onChange={this.handleOptionChange}
                disabled={disabled}
                className={[_s.d, _s.mr10].join(' ')}
              />
            }

            {
              /* : todo : */
              !showResults && <span className={inputClasses} />
            }

            <span
              className={_s.text}
              dangerouslySetInnerHTML={{ __html: titleEmojified }}
            />

            {
              showResults &&
                <span className={_s.mlAuto}>
                  {Math.round(percent)}%
                </span>
            }
          </Text>
        </label>
      </li>
    )
  }

  render() {
    const { poll, intl } = this.props

    if (!poll) return null

    const timeRemaining = poll.get('expired') ?
      intl.formatMessage(messages.closed)
      : <RelativeTimestamp timestamp={poll.get('expires_at')} futureDate />
    const showResults = poll.get('voted') || poll.get('expired')
    const disabled = this.props.disabled || Object.entries(this.state.selected).every(item => !item)

    return (
      <div className={[_s.d, _s.px15, _s.py10].join(' ')}>
        <ul className={[_s.d, _s.listStyleNone].join(' ')}>
          {
            poll.get('options').map((option, i) => this.renderOption(option, i))
          }
        </ul>

        <div className={[_s.d, _s.flexRow, _s.aiCenter].join(' ')}>
          {
            !showResults && me &&
            <Button
              isNarrow
              className={_s.mr10}
              isDisabled={disabled}
              onClick={this.handleVote}
            >
              <Text color='inherit' size='small' className={_s.px10}>
                {intl.formatMessage(messages.vote)}
              </Text>
            </Button>
          }

          <Text color='secondary'>
            <FormattedMessage
              id='poll.total_votes'
              defaultMessage='{count, plural, one {# vote} other {# votes}}'
              values={{
                count: poll.get('votes_count'),
              }}
            />
            {
              poll.get('expires_at') &&
              <React.Fragment>
                <DotTextSeperator />
                <Text color='secondary' className={_s.ml5}>
                  {timeRemaining}
                </Text>
              </React.Fragment>
            }
          </Text>
        </div>
      </div>
    )
  }

}

const mapStateToProps = (state, { pollId }) => ({
  poll: state.getIn(['polls', pollId]),
})

const messages = defineMessages({
  closed: { id: 'poll.closed', defaultMessage: 'Closed' },
  vote: { id: 'poll.vote', defaultMessage: 'Vote' },
  refresh: { id: 'poll.refresh', defaultMessage: 'Refresh' },
})

Poll.propTypes = {
  poll: ImmutablePropTypes.map,
  intl: PropTypes.object.isRequired,
  dispatch: PropTypes.func,
  disabled: PropTypes.bool,
}

export default injectIntl(connect(mapStateToProps)(Poll))