import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { defineMessages, injectIntl } from 'react-intl';
import PresentationUploaderContainer from '/imports/ui/components/presentation/presentation-uploader/container';
import { withModalMounter } from '/imports/ui/components/modal/service';
import _ from 'lodash';
import { Session } from 'meteor/session';
import cx from 'classnames';
import Button from '/imports/ui/components/button/component';
import Checkbox from '/imports/ui/components/checkbox/component';
import LiveResult from './live-result/component';
import { styles } from './styles.scss';
import DragAndDrop from './dragAndDrop/component';

const intlMessages = defineMessages({
  pollPaneTitle: {
    id: 'app.poll.pollPaneTitle',
    description: 'heading label for the poll menu',
  },
  closeLabel: {
    id: 'app.poll.closeLabel',
    description: 'label for poll pane close button',
  },
  hidePollDesc: {
    id: 'app.poll.hidePollDesc',
    description: 'aria label description for hide poll button',
  },
  quickPollInstruction: {
    id: 'app.poll.quickPollInstruction',
    description: 'instructions for using pre configured polls',
  },
  activePollInstruction: {
    id: 'app.poll.activePollInstruction',
    description: 'instructions displayed when a poll is active',
  },
  dragDropPollInstruction: {
    id: 'app.poll.dragDropPollInstruction',
    description: 'instructions for upload poll options via drag and drop',
  },
  ariaInputCount: {
    id: 'app.poll.ariaInputCount',
    description: 'aria label for custom poll input field',
  },
  customPlaceholder: {
    id: 'app.poll.customPlaceholder',
    description: 'custom poll input field placeholder text',
  },
  noPresentationSelected: {
    id: 'app.poll.noPresentationSelected',
    description: 'no presentation label',
  },
  clickHereToSelect: {
    id: 'app.poll.clickHereToSelect',
    description: 'open uploader modal button label',
  },
  questionErr: {
    id: 'app.poll.questionErr',
    description: 'question text area error label',
  },
  optionErr: {
    id: 'app.poll.optionErr',
    description: 'poll input error label',
  },
  tf: {
    id: 'app.poll.tf',
    description: 'label for true / false poll',
  },
  a4: {
    id: 'app.poll.a4',
    description: 'label for A / B / C / D poll',
  },
  delete: {
    id: 'app.poll.optionDelete.label',
    description: '',
  },
  pollPanelDesc: {
    id: 'app.poll.panel.desc',
    description: '',
  },
  questionLabel: {
    id: 'app.poll.question.label',
    description: '',
  },
  userResponse: {
    id: 'app.poll.userResponse.label',
    description: '',
  },
  responseChoices: {
    id: 'app.poll.responseChoices.label',
    description: '',
  },
  typedResponseDesc: {
    id: 'app.poll.typedResponse.desc',
    description: '',
  },
  responseTypesLabel: {
    id: 'app.poll.responseTypes.label',
    description: '',
  },
  addOptionLabel: {
    id: 'app.poll.addItem.label',
    description: '',
  },
  startPollLabel: {
    id: 'app.poll.start.label',
    description: '',
  },
  questionTitle: {
    id: 'app.poll.question.title',
    description: '',
  },
  true: {
    id: 'app.poll.answer.true',
    description: '',
  },
  false: {
    id: 'app.poll.answer.false',
    description: '',
  },
  a: {
    id: 'app.poll.answer.a',
    description: '',
  },
  b: {
    id: 'app.poll.answer.b',
    description: '',
  },
  c: {
    id: 'app.poll.answer.c',
    description: '',
  },
  d: {
    id: 'app.poll.answer.d',
    description: '',
  },
  yna: {
    id: 'app.poll.yna',
    description: '',
  },
  yes: {
    id: 'app.poll.y',
    description: '',
  },
  no: {
    id: 'app.poll.n',
    description: '',
  },
  abstention: {
    id: 'app.poll.abstention',
    description: '',
  },
  enableMultipleResponseLabel: {
    id: 'app.poll.enableMultipleResponseLabel',
    description: 'label for checkbox to enable multiple choice',
  },
});

const CHAT_ENABLED = Meteor.settings.public.chat.enabled;
const MAX_CUSTOM_FIELDS = Meteor.settings.public.poll.max_custom;
const MAX_INPUT_CHARS = 45;
const FILE_DRAG_AND_DROP_ENABLED = Meteor.settings.public.poll.allowDragAndDropFile;

const validateInput = (i) => {
  let _input = i;
  if (/^\s/.test(_input)) _input = '';
  return _input;
};

class Poll extends Component {
  constructor(props) {
    super(props);

    this.state = {
      isPolling: false,
      question: '',
      optList: [],
      error: null,
      isMultipleResponse: false,
    };

    this.handleBackClick = this.handleBackClick.bind(this);
    this.handleAddOption = this.handleAddOption.bind(this);
    this.handleRemoveOption = this.handleRemoveOption.bind(this);
    this.handleTextareaChange = this.handleTextareaChange.bind(this);
    this.handleInputChange = this.handleInputChange.bind(this);
    this.toggleIsMultipleResponse = this.toggleIsMultipleResponse.bind(this);
  }

  componentDidMount() {
    const { props } = this.hideBtn;
    const { className } = props;

    const hideBtn = document.getElementsByClassName(`${className}`);
    if (hideBtn[0]) hideBtn[0].focus();
  }

  componentDidUpdate() {
    const { amIPresenter } = this.props;

    if (Session.equals('resetPollPanel', true)) {
      this.handleBackClick();
    }

    if (!amIPresenter) {
      Session.set('openPanel', 'userlist');
      Session.set('forcePollOpen', false);
    }
  }

  handleBackClick() {
    const { stopPoll } = this.props;
    this.setState({
      isPolling: false,
      error: null,
    }, () => {
      stopPoll();
      Session.set('resetPollPanel', false);
      document.activeElement.blur();
    });
  }

  handleInputChange(index, event) {
    this.handleInputTextChange(index, event.target.value);
  }

  handleInputTextChange(index, text) {
    const { optList } = this.state;
    // This regex will replace any instance of 2 or more consecutive white spaces
    // with a single white space character.
    const option = text.replace(/\s{2,}/g, ' ').trim();

    if (index < optList.length) optList[index].val = option === '' ? '' : option;

    this.setState({ optList });
  }

  handleInputChange(e, index) {
    const { optList, type, error } = this.state;
    const list = [...optList];
    const validatedVal = validateInput(e.target.value).replace(/\s{2,}/g, ' ');
    const clearError = validatedVal.length > 0 && type !== 'RP';
    list[index] = { val: validatedVal };
    this.setState({ optList: list, error: clearError ? null : error });
  }


  toggleIsMultipleResponse() {
    const { isMultipleResponse } = this.state;
    return this.setState({ isMultipleResponse: !isMultipleResponse });
  }


  handleTextareaChange(e) {
    const { type, error } = this.state;
    const validatedQuestion = validateInput(e.target.value);
    const clearError = validatedQuestion.length > 0 && type === 'RP';
    this.setState({ question: validateInput(e.target.value), error: clearError ? null : error });
  }

  pushToCustomPollValues(text) {
    const lines = text.split('\n');
    for (let i = 0; i < MAX_CUSTOM_FIELDS; i += 1) {
      let line = '';
      if (i < lines.length) {
        line = lines[i];
        line = line.length > MAX_INPUT_CHARS ? line.substring(0, MAX_INPUT_CHARS) : line;
      }
      this.handleInputTextChange(i, line);
    }
  }

  handlePollValuesText(text) {
    if (text && text.length > 0) {
      this.pushToCustomPollValues(text);
    }
  }

  handleRemoveOption(index) {
    const { optList } = this.state;
    const list = [...optList];
    list.splice(index, 1);
    this.setState({ optList: list });
  }

  handleAddOption() {
    const { optList } = this.state;
    this.setState({ optList: [...optList, { val: '' }] });
  }

  checkPollType() {
    const { type, optList } = this.state;
    let _type = type;
    let pollString = '';
    let defaultMatch = null;
    let isDefault = null;

    switch (_type) {
      case 'A-':
        pollString = optList.map(x => x.val).sort().join('');
        defaultMatch = pollString.match(/^(ABCDEFG)|(ABCDEF)|(ABCDE)|(ABCD)|(ABC)|(AB)$/gi);
        isDefault = defaultMatch && pollString.length === defaultMatch[0].length;
        _type = isDefault ? `${_type}${defaultMatch[0].length}` : 'custom';
        break;
      case 'TF':
        pollString = optList.map(x => x.val).join('');
        defaultMatch = pollString.match(/^(TRUEFALSE)|(FALSETRUE)$/gi);
        isDefault = defaultMatch && pollString.length === defaultMatch[0].length;
        if (!isDefault) _type = 'custom';
        break;
      case 'YNA':
        pollString = optList.map(x => x.val).join('');
        defaultMatch = pollString.match(/^(YesNoAbstention)$/gi);
        isDefault = defaultMatch && pollString.length === defaultMatch[0].length;
        if (!isDefault) _type = 'custom';
        break;
      default:
        break;
    }
    return _type;
  }

  renderInputs() {
    const { intl } = this.props;
    const { optList, type, error } = this.state;
    let hasVal = false;
    return optList.map((o, i) => {
      if (o.val.length > 0) hasVal = true;
      const pollOptionKey = `poll-option-${i}`;
      return (
        <span>
          <div
            key={pollOptionKey}
            style={{
              display: 'flex',
              justifyContent: 'spaceBetween',
            }}
          >
            <input
              type="text"
              value={o.val}
              placeholder={intl.formatMessage(intlMessages.customPlaceholder)}
              data-test="pollOptionItem"
              className={styles.pollOption}
              onChange={e => this.handleInputChange(e, i)}
              maxLength={MAX_INPUT_CHARS}
            />
            { i > 1 ? (
              <Button
                className={styles.deleteBtn}
                label={intl.formatMessage(intlMessages.delete)}
                icon="delete"
                data-test="deletePollOption"
                hideLabel
                circle
                color="default"
                onClick={() => {
                  this.handleRemoveOption(i);
                }}
              />) : <div style={{ width: '40px' }} />
        }
          </div>
          {!hasVal && type !== 'RP' && error ? (
            <div className={styles.inputError}>{error}</div>
          ) : (
            <div className={styles.errorSpacer}>&nbsp;</div>
          )}
        </span>
      );
    });
  }

  renderActivePollOptions() {
    const {
      intl,
      isMeteorConnected,
      stopPoll,
      currentPoll,
      pollAnswerIds,
    } = this.props;

    return (
      <div>
        <div className={styles.instructions}>
          {intl.formatMessage(intlMessages.activePollInstruction)}
        </div>
        <LiveResult
          {...{
            isMeteorConnected,
            stopPoll,
            currentPoll,
            pollAnswerIds,
          }}
          handleBackClick={this.handleBackClick}
        />
      </div>
    );
  }

  renderPollOptions() {
    const {
      type, optList, question, error, isMultipleResponse,
    } = this.state;
    const { startPoll, startCustomPoll, intl } = this.props;
    const defaultPoll = type === 'TF' || type === 'A-' || type === 'YNA';
    return (
      <div>
        <div className={styles.instructions}>
          {intl.formatMessage(intlMessages.pollPanelDesc)}
        </div>
        <div>
          <h4>{intl.formatMessage(intlMessages.questionTitle)}</h4>
          <textarea
            data-test="pollQuestionArea"
            className={styles.pollQuestion}
            value={question}
            onChange={e => this.handleTextareaChange(e)}
            rows="4"
            cols="35"
            placeholder={intl.formatMessage(intlMessages.questionLabel)}
          />
          {(type === 'RP' && question.length === 0 && error) ? (
            <div className={styles.inputError}>{error}</div>
          ) : (
            <div className={styles.errorSpacer}>&nbsp;</div>
          )}
        </div>
        <div data-test="responseTypes">
          <h4>{intl.formatMessage(intlMessages.responseTypesLabel)}</h4>
          <div className={styles.responseType}>
            <Button
              label={intl.formatMessage(intlMessages.tf)}
              color="default"
              onClick={() => {
                this.setState({
                  type: 'TF',
                  optList: [
                    { val: intl.formatMessage(intlMessages.true) },
                    { val: intl.formatMessage(intlMessages.false) },
                  ],
                });
              }}
              className={cx(styles.pBtn, { [styles.selectedBtn]: type === 'TF' })}
            />
            <Button
              label={intl.formatMessage(intlMessages.a4)}
              color="default"
              onClick={() => {
                this.setState({
                  type: 'A-',
                  optList: [
                    { val: intl.formatMessage(intlMessages.a) },
                    { val: intl.formatMessage(intlMessages.b) },
                    { val: intl.formatMessage(intlMessages.c) },
                    { val: intl.formatMessage(intlMessages.d) },
                  ],
                });
              }}
              className={cx(styles.pBtn, { [styles.selectedBtn]: type === 'A-' })}
            />
          </div>
          <Button
            label={intl.formatMessage(intlMessages.yna)}
            color="default"
            onClick={() => {
              this.setState({
                type: 'YNA',
                optList: [
                  { val: intl.formatMessage(intlMessages.yes) },
                  { val: intl.formatMessage(intlMessages.no) },
                  { val: intl.formatMessage(intlMessages.abstention) },
                ],
              });
            }}
            className={cx(styles.pBtn, styles.yna, { [styles.selectedBtn]: type === 'YNA' })}
          />
          <Button
            label={intl.formatMessage(intlMessages.userResponse)}
            color="default"
            onClick={() => { this.setState({ type: 'RP' }); }}
            className={cx(styles.pBtn, styles.fullWidth, { [styles.selectedBtn]: type === 'RP' })}
          />
        </div>
        { type
              && (
              <div data-test="responseChoices">
                <h4>{intl.formatMessage(intlMessages.responseChoices)}</h4>
                {
                  type === 'RP'
                    && (
                    <div>
                      <span>{intl.formatMessage(intlMessages.typedResponseDesc)}</span>
                      <div className={styles.exampleResponse}>
                        <div className={styles.exampleTitle} />
                        <div className={styles.responseInput}>
                          <div className={styles.rInput} />
                        </div>
                      </div>
                    </div>
                    )
                }
                {
                  (defaultPoll || type === 'RP')
                    && (
                    <div style={{
                      display: 'flex',
                      flexFlow: 'column',
                    }}
                    >
                      {defaultPoll
                        && (
                        <div>
                          <Checkbox
                            onChange={this.toggleIsMultipleResponse}
                            checked={isMultipleResponse}
                            className={styles.checkbox}
                            ariaLabelledBy="multipleResponseCheckboxLabel"
                          />
                          <label id="multipleResponseCheckboxLabel" className={styles.instructions}>
                            {intl.formatMessage(intlMessages.enableMultipleResponseLabel)}
                          </label>
                        </div>
                        )
                      }
                      {defaultPoll && this.renderInputs()}
                      {defaultPoll
                        && (
                        <Button
                          className={styles.addItemBtn}
                          data-test="addItem"
                          label={intl.formatMessage(intlMessages.addOptionLabel)}
                          color="default"
                          icon="add"
                          disabled={optList.length === MAX_CUSTOM_FIELDS}
                          onClick={() => this.handleAddOption()}
                        />
                        )
                      }
                      <Button
                        className={styles.startPollBtn}
                        data-test="startPoll"
                        label={intl.formatMessage(intlMessages.startPollLabel)}
                        color="primary"
                        onClick={() => {
                          let hasVal = false;
                          optList.forEach((o) => {
                            if (o.val.length > 0) hasVal = true;
                          });

                          let err = null;
                          if (type === 'RP' && question.length === 0) err = intl.formatMessage(intlMessages.questionErr);
                          if (!hasVal && type !== 'RP') err = intl.formatMessage(intlMessages.optionErr);
                          if (err) return this.setState({ error: err });

                          this.setState({ isPolling: true }, () => {
                            const verifiedPollType = this.checkPollType();
                            const verifiedOptions = optList.map((o) => {
                              if (o.val.length > 0) return o.val;
                              return null;
                            });
                            if (verifiedPollType === 'custom') {
                              startCustomPoll(
                                verifiedPollType,
                                question,
                                isMultipleResponse,
                                _.compact(verifiedOptions),
                              );
                            } else {
                              startPoll(verifiedPollType, question, isMultipleResponse);
                            }
                          });
                        }}
                      />
                      {
                        FILE_DRAG_AND_DROP_ENABLED && type !== 'RP' && this.renderDragDrop()
                      }
                    </div>
                    )
              }
              </div>
              )
        }
      </div>
    );
  }

  renderNoSlidePanel() {
    const { mountModal, intl } = this.props;
    return (
      <div className={styles.noSlidePanelContainer}>
        <h4>{intl.formatMessage(intlMessages.noPresentationSelected)}</h4>
        <Button
          label={intl.formatMessage(intlMessages.clickHereToSelect)}
          color="primary"
          onClick={() => mountModal(<PresentationUploaderContainer />)}
          className={styles.pollBtn}
        />
      </div>
    );
  }

  renderPollPanel() {
    const { isPolling } = this.state;
    const {
      currentPoll,
      currentSlide,
    } = this.props;

    if (!CHAT_ENABLED && !currentSlide) return this.renderNoSlidePanel();

    if (isPolling || (!isPolling && currentPoll)) {
      return this.renderActivePollOptions();
    }

    return this.renderPollOptions();
  }


  renderDragDrop() {
    const { intl } = this.props;
    return (
      <div>
        <div className={styles.instructions}>
          {intl.formatMessage(intlMessages.dragDropPollInstruction)}
        </div>
        <DragAndDrop
          {...{ intl, MAX_INPUT_CHARS }}
          handlePollValuesText={e => this.handlePollValuesText(e)}
        >
          <div className={styles.dragAndDropPollContainer} />
        </DragAndDrop>
      </div>
    );
  }


  render() {
    const {
      intl,
      stopPoll,
      currentPoll,
      amIPresenter,
    } = this.props;

    if (!amIPresenter) return null;

    return (
      <div>
        <header className={styles.header}>
          <Button
            ref={(node) => { this.hideBtn = node; }}
            data-test="hidePollDesc"
            tabIndex={0}
            label={intl.formatMessage(intlMessages.pollPaneTitle)}
            icon="left_arrow"
            aria-label={intl.formatMessage(intlMessages.hidePollDesc)}
            className={styles.hideBtn}
            onClick={() => { Session.set('openPanel', 'userlist'); }}
          />
          <Button
            label={intl.formatMessage(intlMessages.closeLabel)}
            aria-label={`${intl.formatMessage(intlMessages.closeLabel)} ${intl.formatMessage(intlMessages.pollPaneTitle)}`}
            onClick={() => {
              if (currentPoll) stopPoll();
              Session.set('openPanel', 'userlist');
              Session.set('forcePollOpen', false);
              Session.set('pollInitiated', false);
            }}
            className={styles.closeBtn}
            icon="close"
            size="sm"
            hideLabel
          />
        </header>
        {this.renderPollPanel()}
      </div>
    );
  }
}

export default withModalMounter(injectIntl(Poll));

Poll.propTypes = {
  intl: PropTypes.shape({
    formatMessage: PropTypes.func.isRequired,
  }).isRequired,
  amIPresenter: PropTypes.bool.isRequired,
  pollTypes: PropTypes.instanceOf(Array).isRequired,
  startPoll: PropTypes.func.isRequired,
  startCustomPoll: PropTypes.func.isRequired,
  stopPoll: PropTypes.func.isRequired,
};
