import _ from 'lodash';
import Immutable from 'immutable';
import React from 'react';
import { block } from 'bem-cn';
import Loader from 'ui-components/lib/Loader';
import { TextInput, Button } from 'lego-on-react';
import FormMixin from 'lib/FormMixin';
import { i18n } from 'lib/i18n';

import Form from 'ui/Form';
import CaptchaContainer from 'components/Captcha';

import KeyCodes from 'constants/KeyCodes';

import ConfigStore from 'stores/Config';
import CaptchaStore from 'stores/Captcha';
import AuthStore from 'stores/Auth';

import CaptchaActions from 'actions/Captcha';

import InvitesActions from 'actions/Invite';
import inviteValidator from 'validation/invite';
import InputItem from './components/InputItem';

import './index.css';

const bInviteForm = block('invite-form');

const InviteForm = React.createClass({

    mixins: [FormMixin],

    getInitialState() {
        return {
            errors: inviteValidator.getErrors(),
            emailList: [],
            inputContent: '',
            isLoading: false,
            captchaText: '',
        };
    },

    componentDidMount() {
        this.focusInput();
    },

    _getData() {
        const isCaptchaRequired = AuthStore.isCaptchaRequired();
        const { departmentId } = this.props;
        const { emailList, captchaText } = this.state;
        const inviteData = {
            emails: emailList,
            department_id: Number(departmentId),
            tld: ConfigStore.get('app.tld'),
        };

        if (isCaptchaRequired) {
            inviteData.key = CaptchaStore.getKey();
            inviteData.rep = captchaText;
        }

        return inviteData;
    },

    _invite() {
        const { onSubmit } = this.props;

        this.setState({
            isLoading: true,
        });

        const inviteData = this._getData();
        const isCaptchaRequired = AuthStore.isCaptchaRequired();

        InvitesActions.inviteByEmails(inviteData)
            .then(({ errors }) => {
                if (errors && !errors.isEmpty()) {
                    if (isCaptchaRequired) {
                        CaptchaActions.refresh()
                            .finally(() => {
                                this.setState({
                                    captchaText: '',
                                    isLoading: false,
                                    errors,
                                });
                            });
                    } else {
                        this.setState({
                            isLoading: false,
                            errors,
                        });
                    }
                } else {
                    this.setState({ isLoading: false });

                    onSubmit();
                }
            })
            .catch(() => {
                this.setState({ isLoading: false });
            });
    },

    focusInput() {
        const input = this._getInputRef();

        this.setState({ errors: new Immutable.Map() });
        input.focus();
    },

    _setInputRef(input) {
        this._input = input;
    },

    _getInputRef() {
        return this._input;
    },

    _onChange(inputContent) {
        this.setState({ inputContent });
    },

    _onInput(event) {
        if (event.keyCode === KeyCodes.ENTER) {
            return this._validateInput();
        }
    },

    _validateInput(callback) {
        const { inputContent, emailList } = this.state;

        const splitEmails = inputContent
            .trim()
            .split(/[\s,;]+/)
            .filter(Boolean);

        if (this._use(inviteValidator)._validate({ splitEmails, emailList })) {
            this.setState({
                emailList: _.uniq(emailList.concat(splitEmails)),
                inputContent: '',
            }, () => {
                if (callback) {
                    callback();
                }
            });
        }
    },

    _removeEmail(emailToRemove) {
        const { emailList } = this.state;

        this.setState({
            emailList: emailList.filter(email => email !== emailToRemove),
        });
    },

    _getErrorContent() {
        const errors = this.state.errors.toJS();

        return errors.captcha || errors.emails || errors._common || errors.emailList;
    },

    _getEmailList() {
        const { emailList } = this.state;

        if (!emailList) {
            return null;
        }

        return emailList.map(email => (
            <div className={bInviteForm('item')} key={email}>
                <InputItem
                    onRemove={() => this._removeEmail(email)}
                    key={email}
                    content={email}
                />
            </div>
        ));
    },

    _onControlCLick() {
        this.focusInput();
    },

    _onTextInputFocus() {
        this.setState({ focused: true });
    },

    _onTextInputBlur() {
        this.setState({ focused: false });
    },

    _onSubmitButtonClick() {
        this._validateInput(this._invite);
    },

    onCaptchaTextChange(captchaText) {
        this.setState({ captchaText });
    },

    _canSubmit() {
        const { inputContent, emailList, captchaText } = this.state;
        const isCaptchaRequired = AuthStore.isCaptchaRequired();

        return (inputContent.length || emailList.length) && (!isCaptchaRequired || captchaText.length > 5);
    },

    _renderCaptcha() {
        const isCaptchaRequired = AuthStore.isCaptchaRequired();
        const { captchaText } = this.state;

        if (!isCaptchaRequired) {
            return null;
        }

        return (
            <div className={bInviteForm('captcha')}>
                <CaptchaContainer
                    text={captchaText}
                    onChange={this.onCaptchaTextChange}
                />
            </div>
        );
    },

    render() {
        const { isLoading, inputContent, focused } = this.state;
        const { label, buttonText, buttonWidth = 'auto' } = this.props;
        let labelContent;

        if (label) {
            labelContent = (
                <div className={bInviteForm('input-label')}>
                    {label}
                </div>
            );
        }

        return (
            <div className={bInviteForm()}>
                <Loader visible={isLoading} />
                {labelContent}
                <div
                    className={bInviteForm('control', { focused: focused ? 'yes' : 'no' })}
                    onClick={this._onControlCLick}
                >
                    <div className={bInviteForm('email-list')}>
                        {this._getEmailList()}
                        <TextInput
                            ref={this._setInputRef}
                            key="input"
                            theme="normal"
                            size="s"
                            mix={{
                                block: 'invite-form',
                                elem: 'textinput',
                            }}
                            text={inputContent}
                            focused
                            autoComplete={false}
                            onFocus={this._onTextInputFocus}
                            onBlur={this._onTextInputBlur}
                            onKeyDown={this._onInput}
                            onChange={this._onChange}
                            placeholder={i18n('invites.inputs.placeholder')}
                        />
                    </div>
                </div>
                {this._renderCaptcha()}
                <Form.Error value={this._getErrorContent()} mod="standalone" />
                <Button
                    theme="action"
                    view="default"
                    tone="default"
                    size="m"
                    width={buttonWidth}
                    disabled={!this._canSubmit()}
                    mix={{
                        block: 'invite-form',
                        elem: 'button',
                    }}
                    onClick={this._onSubmitButtonClick}
                >
                    {buttonText}
                </Button>
            </div>
        );
    },
});

export default InviteForm;
