import _ from 'lodash';
import PropTypes from 'prop-types';
import React from 'react';
import { Button } from 'lego-on-react';
import Suggest from 'ui-components/lib/Suggest';
import Loader from 'ui-components/lib/Loader';
import FormMixin from 'lib/FormMixin';
import StoreMixin from 'lib/StoreMixin';

import SubscriptionStore from 'stores/Subscription';
import LicenseStore from 'stores/Licenses';
import ConfigStore from 'stores/Config';
import AuthStore from 'stores/Auth';

import LicenseActions from 'actions/Licenses';
import ModalActions from 'actions/Modal';

import { i18n, formatCurrency, pluralize } from 'lib/i18n';
import { toRecord, toCompactObject } from 'records/util';

import Unit from 'ui/Unit';
import Icon from 'ui/Icon';
import Tip from 'ui/Tip';
import Link from 'ui/Link';
import CreateUserForm from 'components/User/Forms/Create';

import SuggestService from 'services/suggest';
import notify from 'services/notify';
import Metrika from 'lib/metrika';

import './index.css';

const SUGGEST_LIMIT = 10;

const SUGGEST_ADD_NEW_USER_ITEM = {
    type: 'add_subscribers',
    isTechnical: true,
};

const SUGGEST_ITEM_NO_RESULTS = {
    type: 'no_results',
    isTechnical: true,
};

const SUGGEST_ITEM_DELIMITER = {
    type: 'delimiter',
    isTechnical: true,
};

const AddSubscribers = React.createClass({

    mixins: [FormMixin, StoreMixin],

    getStoreState() {
        const serviceSlug = this.props.id;
        const pricing = SubscriptionStore.getPricing(serviceSlug) || {};

        return {
            selectedView: 'search',
            currentSubscribers: (LicenseStore.getCurrentSubscribers(serviceSlug) || []).map(toRecord),
            currentSubscribersCount: SubscriptionStore.getCurrentUserCount(serviceSlug),
            currentPricePerUser: pricing.per_user_with_discount || pricing.per_user,
            currentTotalPrice: pricing.total_with_discount || pricing.total,
            currency: pricing.currency,
            newSubscribers: _.get(this.state, 'newSubscribers', []),
            newSubscribersCount: _.get(this.state, 'newSubscribersCount', 0),
            newPricePerUser: _.get(this.state, 'newPricePerUser'),
            newTotalPrice: _.get(this.state, 'newTotal'),
            userLimit: _.get(AuthStore.getService(serviceSlug), 'user_limit'),
            suggestType: AuthStore.isPartnerOrganization() || serviceSlug === 'disk' ? 'user' : null,
        };
    },

    componentDidMount() {
        this.subscribe([SubscriptionStore, LicenseStore, AuthStore]);
        this._suggest = this.refs.suggest;
    },

    _onFocus() {
        if (!_.get(this._suggest, 'refs.input.value', '')) {
            this._suggest._lastValue = '';
            this._suggest._search('');
        }
    },

    _handleUserAdded(data) {
        const { newSubscribers } = this.state;

        if (data && data.users) {
            const addedSubscribers = Object.keys(data.users).map(id => toRecord({ id, type: 'user' }));

            this.setState({
                selectedView: 'search',
            });

            this._updateNewSubscribers(newSubscribers.concat(addedSubscribers));
        }
    },

    _handleAddUserBackClick() {
        this.setState({
            selectedView: 'search',
        });
    },

    /**
     * Получает данные для саджеста и передает их callback
     * @param {String} text
     * @param {function} next
     * @private
     */
    _getSource(text, next) {
        const { suggestType } = this.state;
        const suggestParams = { text, limit: SUGGEST_LIMIT };

        if (suggestType) {
            suggestParams.types = [suggestType];
        }

        if (!text) {
            SuggestService.searchLicenses(suggestType, next);

            return;
        }

        const callBack = (error, results) => {
            if (results.length === 0) {
                results = [
                    {
                        sectionName: null,
                        suggestions: [
                            SUGGEST_ITEM_NO_RESULTS,
                            SUGGEST_ITEM_DELIMITER,
                            SUGGEST_ADD_NEW_USER_ITEM,
                        ],
                    },
                ];
            }

            next(error, results);
        };

        SuggestService.search(suggestParams, callBack);
    },

    _renderSuggestItem(payload) {
        const item = payload.item;

        if (payload.isTechnical) {
            return this._renderSpecialSuggestItem(payload);
        }

        const isAdded = this._isItemAdded(item);
        const name = item.getAlphabeticalName ? item.getAlphabeticalName() : item.getName();
        let description = item.getDescription();
        let status = null;

        if (item.getMemberCount) {
            description = pluralize(item.getMemberCount(), i18n('balance.services.persons'));
        }

        if (isAdded) {
            status = (
                <div className="add-subscribers__suggest-item-tooltip">
                    <Icon type="ok-grey" size="m" />

                    <Tip theme="light">
                        <div className="add-subscribers__suggest-item-tooltip-content">
                            {i18n('licenses.subscribed')}
                        </div>
                    </Tip>
                </div>
            );
        }

        return (
            <div className="add-subscribers__suggest-item">
                <div className="add-subscribers__suggest-item-body">
                    <Unit
                        size="m"
                        avatar={item.getAvatar()}
                        showDescription
                        description={description}
                        title={name}
                    />
                </div>
                {status}
            </div>
        );
    },

    _renderSpecialSuggestItem(item) {
        const { type } = item;
        let content = null;

        switch (type) {
            case 'add_subscribers':
                content = (
                    <span className="add-subscribers__pseudo-link">
                        {i18n('licenses.add_new_user')}
                    </span>
                );
                break;
            case 'no_results':
                content = i18n('licenses.not_found_person');
                break;
            case 'delimiter':
                return (
                    <div className="add-subscribers__suggest-item_technical add-subscribers__suggest-item_delimiter" />
                );
        }

        return (
            <div className="add-subscribers__suggest-item_technical">
                {content}
            </div>
        );
    },

    _isItemAdded(item) {
        const { currentSubscribers, newSubscribers } = this.state;
        const id = item.getId();
        const type = item.getType();

        const addedList = currentSubscribers
            .concat(newSubscribers)
            .filter(currentItem => currentItem.getId() === id && currentItem.getType() === type);

        return addedList.length > 0;
    },

    _isSuggestItemActive(data) {
        if (data.isTechnical) {
            return data.type === SUGGEST_ADD_NEW_USER_ITEM.type;
        }

        return !this._isItemAdded(data.item);
    },

    _handleSuggestSelect(data) {
        const { item } = data;

        if (data.isTechnical) {
            if (data.type === 'add_subscribers') {
                this.setState({
                    selectedView: 'new_subscriber',
                });
            }

            return;
        }

        if (this._isItemAdded(item)) {
            return;
        }

        const { newSubscribers } = this.state;

        newSubscribers.push(item);

        this._updateNewSubscribers(newSubscribers);
    },

    _hasNewSubscribers() {
        return this.state.newSubscribers.length > 0;
    },

    _renderSearch() {
        const { selectedView, isLoading, suggestType } = this.state;
        let classes = 'add-subscribers__search';

        if (selectedView !== 'search') {
            classes += ' add-subscribers__search_hidden';
        }

        return (
            <div className={classes}>
                <h3 className="add-subscribers__title">
                    {i18n('licenses.add_subscribers.title.search')}
                </h3>
                <div className="add-subscribers__suggest">
                    <Suggest
                        popupClassName="add-subscribers__suggest-list"
                        source={this._getSource}
                        type={suggestType}
                        minLength={0}
                        timeout={200}
                        renderItem={this._renderSuggestItem}
                        isItemActive={this._isSuggestItemActive}
                        onFocus={this._onFocus}
                        onSelect={this._handleSuggestSelect}
                        placeholder={i18n(`common.suggest_search_placeholder.${suggestType || 'default'}`)}
                        ref="suggest"
                    />
                </div>
                {this._renderNewItemList()}
                <div className="add-subscribers__footer">
                    <Button
                        text={i18n('licenses.save_subscriptions')}
                        theme="action"
                        size="m"
                        disabled={!this._hasNewSubscribers()}
                        onClick={this._saveLicenses}
                    />
                    {AuthStore.isPartnerOrganization() ? this._renderCounter() : this._renderPriceDetails()}
                </div>
                <Loader visible={isLoading} size="m" />
            </div>
        );
    },

    _renderCounter() {
        if (!this._hasNewSubscribers()) {
            return null;
        }

        const { newSubscribersCount, userLimit } = this.state;
        const counterContent = i18n('licenses.user_counter.limit', {
            available_subscriptions: pluralize(
                userLimit,
                i18n('licenses.user_counter.available_subscriptions')
            ),
        });

        return (
            <div className="add-subscribers__price-details">
                <span className="add-subscribers__price-details-title">
                    {pluralize(newSubscribersCount, i18n('licenses.user_counter.subscription'))}
                </span>
                <br />
                <span className="add-subscribers__price-details-description">
                    {counterContent}
                </span>
                <Loader visible={this.state.isPriceLoading} size="s" />
            </div>
        );
    },

    _renderPriceDetails() {
        if (!this._hasNewSubscribers()) {
            return null;
        }

        const {
            newPricePerUser,
            currentPricePerUser,
            currency,
            newSubscribersCount,
            currentSubscribersCount,
            currentTotalPrice,
            newTotalPrice,
        } = this.state;

        const price = formatCurrency(newPricePerUser || currentPricePerUser, currency);
        const total = formatCurrency(newTotalPrice || currentTotalPrice, currency);
        let tip = null;

        if (newPricePerUser && newPricePerUser !== currentPricePerUser) {
            tip = (
                <div className="add-subscribers__price-details-tooltip">
                    <Icon type="blue-info" />

                    <Tip theme="light" position="top-right">
                        <div className="add-subscribers__price-details-tooltip-content">
                            <div className="">
                                <p
                                    dangerouslySetInnerHTML={{
                                        __html: i18n('licenses.changed_price_tooltip.text', {
                                            price,
                                            total,
                                            n_subscriptions: pluralize(newSubscribersCount - currentSubscribersCount,
                                                i18n('licenses.count_subscriptions')),
                                            n_subscriptions_new: pluralize(newSubscribersCount,
                                                i18n('licenses.count_subscriptions')),
                                            // TODO выпилить count, когда из en и tr ключей уберут этот параметр
                                            count: newSubscribersCount,
                                        }),
                                    }}
                                />
                                <Link
                                    className="licenses__link licenses__link_external"
                                    to={ConfigStore.get(`ui.about.${this.props.id}`)}
                                >

                                    {i18n('licenses.changed_price_tooltip.link')}
                                </Link>
                            </div>
                        </div>
                    </Tip>
                </div>
            );
        }

        return (
            <div className="add-subscribers__price-details">
                <span className="add-subscribers__price-details-title">
                    {i18n('licenses.your_tariff')}
                </span>
                <br />
                <span
                    className="add-subscribers__price-details-description"
                    dangerouslySetInnerHTML={{
                        __html: i18n('licenses.your_tariff_per_user', { price }),
                    }}
                />
                {tip}
                <Loader visible={this.state.isPriceLoading} size="s" />
            </div>
        );
    },

    _initSearchPlaceholder(element) {
        let pseudoLink = element && element.querySelector('.pseudo-link');

        if (pseudoLink) {
            pseudoLink.addEventListener('click', this._onClickAddNewUser);
        }
    },

    _renderNewItemList() {
        const { newSubscribers } = this.state;

        if (newSubscribers.length === 0) {
            return (
                <div
                    className="add-subscribers__content add-subscribers__empty-search"
                    ref={this._initSearchPlaceholder}
                >
                    <div className="add-subscribers__empty-search-image" />
                    <p
                        className="add-subscribers__empty-search-description"
                        dangerouslySetInnerHTML={{
                            __html: i18n(`licenses.empty_search_description.${this.props.id}`),
                        }}
                    />
                </div>
            );
        }

        return (
            <div className="add-subscribers__content">
                {this.state.newSubscribers.map(this._renderNewItem)}
            </div>
        );
    },

    _onClickAddNewUser(event) {
        event.preventDefault();

        this.setState({
            selectedView: 'new_subscriber',
        });
    },

    _renderNewItem(item) {
        const name = item.getAlphabeticalName ? item.getAlphabeticalName() : item.getName();
        let description = item.getDescription();

        if (item.getMemberCount) {
            description = pluralize(item.getMemberCount(), i18n('balance.services.persons'));
        }

        return (
            <div className="add-subscribers__list-item" key={`${item.getType()}_${item.getId()}`}>
                <div className="add-subscribers__list-item-body">
                    <Unit
                        size="m"
                        avatar={item.getAvatar()}
                        avatarTooltip={item.getType() === 'user' ? null : i18n('licenses.container_tooltip')}
                        tooltip={false}
                        showDescription
                        description={description}
                        title={name}
                    />
                </div>
                <div className="add-subscribers__list-item-action" onClick={this._removeNewItem.bind(this, item)}>
                    <Icon type="trash" size="l" />
                </div>
            </div>
        );
    },

    _removeNewItem(removedItem) {
        let { newSubscribers } = this.state;

        newSubscribers = newSubscribers.filter(item => removedItem.getId() !== item.getId() ||
            removedItem.getType() !== item.getType());

        this._updateNewSubscribers(newSubscribers);
    },

    _updateNewSubscribers(newSubscribers) {
        const updatedData = { newSubscribers };
        const serviceSlug = this.props.id;

        if (newSubscribers.length > 0) {
            updatedData.isPriceLoading = true;
            const subscribers = this.state.currentSubscribers.concat(newSubscribers);

            LicenseActions.calculate(this.props.id, subscribers)
                .then(response => {
                    const subscriptionData = _.get(response, `subscription.pricing.services.${serviceSlug}`, {});

                    this.setState({
                        newPricePerUser: subscriptionData.per_user_with_discount || subscriptionData.per_user,
                        newTotalPrice: subscriptionData.total_with_discount || subscriptionData.total,
                        newSubscribersCount: subscriptionData.users_count,
                        isPriceLoading: false,
                    });
                })
                .catch(() => {
                    this.setState({
                        isPriceLoading: false,
                    });
                });
        }

        this.setState(updatedData);
    },

    _saveLicenses() {
        const { currentSubscribers, newSubscribers } = this.state;
        const draftSubscribers = {
            [this.props.id]: currentSubscribers.concat(newSubscribers).map(toCompactObject),
        };

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

        return LicenseActions.update(this.props.id, { subscribers: draftSubscribers })
            .then(data => {
                if (data.errors) {
                    return notify(i18n('licenses.add.error'), 'error');
                }

                return data;
            })
            .then(() => {
                ModalActions.close();
                Metrika.reachGoal('AddPaidUsers');
                notify(i18n('licenses.add.success'), 'success');
            })
            .catch(() => {
                this.setState({
                    isLoading: false,
                });

                return notify(i18n('licenses.add.error'), 'error');
            });
    },

    _renderCreateUser() {
        const { selectedView } = this.state;

        if (selectedView !== 'new_subscriber') {
            return null;
        }

        return (
            <div className="add-subscribers__create-user">
                <h3 className="add-subscribers__title">
                    <span className="add-subscribers__title-control" onClick={this._handleAddUserBackClick} />
                    {i18n('licenses.add_subscribers.title.create_user')}
                </h3>
                <CreateUserForm
                    onSubmit={this._handleUserAdded}
                    submitButtonText="Добавить и оформить подписку"
                    removeCancelButton
                    redirect={false}
                    notifications={false}
                />
            </div>
        );
    },

    render() {
        return (
            <div className="add-subscribers">
                {this._renderSearch()}
                {this._renderCreateUser()}
            </div>
        );
    },

});

AddSubscribers.propTypes = {
    id: PropTypes.string,
    onSubmit: PropTypes.func,
    onCancel: PropTypes.func,
};

export default AddSubscribers;
