import _ from 'lodash';
import moment from 'moment';
import React from 'react';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import classSet from 'classnames';
import { Button, Checkbox } from 'lego-on-react';
import Avatar from 'ui-components/lib/Avatar';
import Loader from 'ui-components/lib/Loader';
import { TRIAL_STATUS } from 'constants/Services';
import StoreMixin from 'lib/StoreMixin';
import { i18n, pluralize, formatDate } from 'lib/i18n';
import { toRecord } from 'records/util';

import StatusBarActions from 'actions/StatusBar';
import SubscriptionActions from 'actions/Subscription';
import LicenseActions from 'actions/Licenses';
import LicenseRequestsActions from 'actions/LicenseRequests';
import ModalActions from 'actions/Modal';

import SubscriptionStore from 'stores/Subscription';
import LicenseStore from 'stores/Licenses';
import AuthStore from 'stores/Auth';
import PermissionStore from 'stores/Permissions';

import notify from 'services/notify';
import ChangePrice from './ChangePrice';

const REQUEST_ACTIONS = {
    CONFIRM: 'confirm',
    DENY: 'deny',
};

const RequestsList = React.createClass({

    mixins: [StoreMixin, PureRenderMixin],

    getStoreState() {
        const serviceName = this.props.serviceSlug;
        const requests = LicenseStore.getRequests(serviceName);
        const pricing = SubscriptionStore.getPricing(serviceName);

        this._mountHook = Promise.resolve();

        return {
            serviceName,
            pricing,
            currency: SubscriptionStore.getCurrency(),
            isContractAvailable: SubscriptionStore.hasContract(),
            requests,
            requestRecordsList: requests.map(toRecord),
            requestCount: LicenseStore.getRequestsCount(serviceName),
            subscribers: LicenseStore.getCurrentSubscribers(serviceName),
            selectedItems: _.get(this.state, 'selectedItems', []),
            isAllChecked: _.get(this.state, 'isAllChecked', false),
            authors: this._generateAuthorsMap(requests),
            isLoading: _.get(this.state, 'isLoading', false),
            trialStatus: AuthStore.getServiceTrialStatus(serviceName),
            isReady: true,
        };
    },

    componentDidMount() {
        this.subscribe([SubscriptionStore, LicenseStore]);

        this._update();
    },

    componentWillUnmount() {
        this._mountHook = new Promise(() => {
            // Noop
        });
    },

    _update() {
        this.setState({ isReady: false });

        LicenseRequestsActions.read()
            .finally(() => this._mountHook)
            .then(() => {
                this.setState({
                    isReady: true,
                });
            });
    },

    _generateAuthorsMap(requests) {
        return requests.reduce((result, item) => {
            result[`${item.type}_${item.id}`] = toRecord({
                type: 'user',
                id: Number(item.author_id),
            });

            return result;
        }, {});
    },

    _getAuthor(item) {
        return this.state.authors[`${item.type}_${item.id}`];
    },

    _isRequestsListEmpty() {
        return this.state.requests.length === 0;
    },

    _onToggleAll(event) {
        const { target } = event;
        const selectedItems = target.checked ? this.state.requests : [];

        this.setState({
            isAllChecked: target.checked,
        });

        this._updateSelectedItems(selectedItems);
    },

    _renderList() {
        return (
            <div>
                {this.state.requests.map(this._renderListItem)}
            </div>
        );
    },

    _getCreatedDate(date) {
        const currentDate = new Date();
        const requestDate = new Date(date);

        if (currentDate.getFullYear() !== requestDate.getFullYear()) {
            return moment(date).locale(AuthStore.getLocale()).format('LL');
        }

        if (currentDate.getMonth() === requestDate.getMonth() && currentDate.getDate() === requestDate.getDate()) {
            return moment(date).locale(AuthStore.getLocale()).format('HH:mm');
        }

        return formatDate(requestDate, 'day-and-month');
    },

    _renderListItem(item, index) {
        const compactItemData = { id: Number(item.id), type: item.type };
        const itemRecord = this.state.requestRecordsList[index];
        const isSelected = this._isSelectedItem(compactItemData);
        const classes = classSet({
            'license-requests__list-item': true,
            action: true,
        });

        const author = this._getAuthor(item);
        const requestDate = this._getCreatedDate(item.created_at);

        const itemName = itemRecord.getAlphabeticalName ? itemRecord.getAlphabeticalName() : itemRecord.getName();
        const description = itemRecord.get('members_count') !== undefined ?
            pluralize(itemRecord.get('members_count'), i18n('balance.services.persons')) :
            itemRecord.getDescription();
        const allowsTrackerManagement = PermissionStore.allowsTrackerManagement();
        const component = {};

        if (allowsTrackerManagement) {
            component.controls = (
                <div className="license-requests__list-item-controls">
                    <Button
                        theme="normal"
                        size="m"
                        text={i18n('license_requests.action_text.deny')}
                        onClick={this._onRemoveOneItem.bind(this, compactItemData)}
                    />
                    <Button
                        theme="action"
                        size="m"
                        text={i18n('license_requests.action_text.confirm')}
                        onClick={this._onSubscribeOneItem.bind(this, compactItemData)}
                    />
                </div>
            );

            component.checkbox = (
                <Checkbox
                    size="m"
                    theme="normal"
                    onChange={this._onListItemClick.bind(this, compactItemData)}
                    checked={isSelected}
                />
            );
        }

        return (
            <div
                className={classes}
                key={`${item.type}_${item.id}`}
            >

                <div className="license-requests__column license-requests__name">
                    {component.checkbox}
                    <Avatar url={itemRecord.getAvatar()} />
                    <div className="license-requests__item-info">
                        <span className="license-requests__item-info-name" title={itemName}>
                            {itemName}
                        </span>
                        <span className="license-requests__item-info-description" title={description}>
                            {description}
                        </span>
                    </div>
                </div>
                <div className="license-requests__column license-requests__author">
                    <span className="license-requests__author-name" title={author.getAlphabeticalName()}>
                        {author.getAlphabeticalName()}
                    </span>
                    <span className="license-requests__author-request-date">
                        {requestDate}
                    </span>
                </div>
                <div className="license-requests__column license-requests__comment" title={item.comment}>
                    {item.comment}
                </div>
                {component.controls}
            </div>
        );
    },

    _onSubscribeOneItem(itemData, event) {
        event.stopPropagation();

        this._deselectItem(itemData);

        this._updateRequests(REQUEST_ACTIONS.CONFIRM, [itemData]);
    },

    _onRemoveOneItem(itemData, event) {
        event.stopPropagation();

        this._deselectItem(itemData);

        this._updateRequests(REQUEST_ACTIONS.DENY, [itemData]);
    },

    _onListItemClick(data, event) {
        event.stopPropagation();

        this._toggleListItem(data);
    },

    _toggleListItem(data) {
        const isSelected = this._isSelectedItem(data);

        return isSelected ? this._deselectItem(data) : this._selectItem(data);
    },

    _selectItem(data) {
        const { selectedItems } = this.state;

        this._updateSelectedItems(selectedItems.concat([data]));
    },

    _deselectItem(data) {
        let { selectedItems } = this.state;
        const { isAllChecked } = this.state;

        selectedItems = selectedItems.filter(item => Number(item.id) !== Number(data.id) || item.type !== data.type);

        if (isAllChecked) {
            this.setState({ isAllChecked: false });
        }

        this._updateSelectedItems(selectedItems);
    },

    _updateSelectedItems(selectedItems) {
        this.setState({ selectedItems });

        if (selectedItems.length === 0) {
            return StatusBarActions.clear();
        }

        const { serviceName } = this.state;
        const isUsers = selectedItems.reduce((result, item) => result && item.type === 'user', true);

        const statusBarData = {
            confirmText: i18n('license_requests.status_bar.confirm_text'),
            rejectText: i18n('license_requests.status_bar.reject_text'),
            onConfirm: this._onStatusBarConfirm,
            onReject: this._onStatusBarReject,
            onClose: this._deselectAll,
        };

        if (selectedItems.length === 1) {
            const count = selectedItems[0].type === 'user' ?
                selectedItems.length :
                toRecord(selectedItems[0]).get('members_count');

            statusBarData.message = this._getSelectedSubscriptionText(count);

            return StatusBarActions.add(statusBarData);
        }

        if (isUsers) {
            statusBarData.message = this._getSelectedSubscriptionText(selectedItems.length);

            return StatusBarActions.add(statusBarData);
        }

        statusBarData.message = i18n('licenses.subscription_counting');
        StatusBarActions.add(statusBarData);

        LicenseActions.calculate(serviceName, selectedItems)
            .then(response => {
                const subscriptionData = _.get(response, `subscription.pricing.services.${serviceName}`, {});

                if (selectedItems === this.state.selectedItems) {
                    const message = this._getSelectedSubscriptionText(subscriptionData.users_count);

                    StatusBarActions.add(_.extend({}, statusBarData, { message }));
                }
            })
            .catch(() => {
                const message = i18n('licenses.selected_several_element', {
                    n_elements: pluralize(selectedItems.length, i18n('licenses.elements')),
                });

                StatusBarActions.add(_.extend({}, statusBarData, { message }));
            });
    },

    _getSelectedSubscriptionText(count) {
        if (count === 1) {
            return i18n('licenses.selected_one_subscription');
        }

        return i18n('licenses.selected_several_subscriptions', {
            n_subscriptions: pluralize(count, i18n('balance.services.subscriptions')),
        });
    },

    _onStatusBarConfirm() {
        this._updateRequests(REQUEST_ACTIONS.CONFIRM);
    },

    _onStatusBarReject() {
        this._updateRequests(REQUEST_ACTIONS.DENY);
    },

    _deselectAll() {
        this.setState({
            isAllChecked: false,
        });

        this._updateSelectedItems([]);
    },

    _isSelectedItem(data, selectedItems = this.state.selectedItems) {
        const matches = selectedItems.filter(item => Number(item.id) === Number(data.id) && item.type === data.type);

        return matches.length > 0;
    },

    _updateRequests(action, selectedItems = this.state.selectedItems) {
        const { serviceName, subscribers, pricing, isContractAvailable, trialStatus } = this.state;
        let checkPricePromise;

        if (!isContractAvailable) {
            return ModalActions.confirm({
                title: i18n('licenses.paid_info_popup.title'),
                message: trialStatus === TRIAL_STATUS.IN_PROGRESS ?
                    i18n('licenses.paid_info_popup.description_for_trial') :
                    i18n('licenses.paid_info_popup.description'),
                confirmButtonText: i18n('licenses.paid_info_popup.confirm_button'),
                onConfirm() {
                    SubscriptionActions.toAgreement(`${serviceName}.requests`);
                },
            });
        }

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

        if (action === REQUEST_ACTIONS.CONFIRM) {
            checkPricePromise = LicenseActions.calculate(serviceName, subscribers.concat(selectedItems))
                .then(response => {
                    const subscriptionData = _.get(response, `subscription.pricing.services.${serviceName}`, {});
                    const currentPricePerUser = pricing.per_user_with_discount || pricing.per_user;
                    const newPricePerUser = subscriptionData.per_user_with_discount || subscriptionData.per_user;

                    if (newPricePerUser === currentPricePerUser) {
                        return;
                    }

                    return this._showChangePricePopup(subscriptionData);
                });
        } else {
            checkPricePromise = Promise.resolve();
        }

        return checkPricePromise.then(() => LicenseRequestsActions.update({
            action,
            requests: selectedItems,
        }))
            .then(() => {
                this._deselectAll();

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

                notify(i18n(`license_requests.${action}.success`), 'success');
            })
            .catch(error => {
                this.setState({
                    isLoading: false,
                });

                if (error && error.code === 'cancelByUser') {
                    return;
                }

                notify(i18n(`license_requests.${action}.error`), 'error');
            });
    },

    _showChangePricePopup(newPricing) {
        const { serviceName, pricing: currentPricing, currency } = this.state;

        return new Promise((resolve, reject) => {
            ModalActions.open({
                title: i18n('license_requests.change_price.title'),
                component: ChangePrice,
                props: {
                    serviceName,
                    currentPricing,
                    newPricing,
                    currency,
                    onConfirm: () => {
                        resolve();
                        ModalActions.close();
                    },
                },
                onClose: () => reject({ code: 'cancelByUser' }),
            });
        });
    },

    render() {
        const { requestCount, isAllChecked, isReady } = this.state;

        if (!isReady) {
            return (
                <div className="license-requests">
                    <Loader visible />
                </div>
            );
        }

        if (this._isRequestsListEmpty()) {
            return (
                <div className="license-requests-empty">
                    <div className="license-requests-empty__image" />
                    <h3 className="license-requests-empty__title">
                        {i18n('license_requests.empty.title')}
                    </h3>
                    <p className="license-requests-empty__description">
                        {i18n('license_requests.empty.description')}
                    </p>
                </div>
            );
        }

        let toggle;

        if (PermissionStore.allowsTrackerManagement()) {
            toggle = (
                <Checkbox
                    size="m"
                    theme="normal"
                    checked={isAllChecked}
                    disabled={false}
                    onChange={this._onToggleAll}
                />
            );
        }

        return (
            <div className="license-requests">
                <h3 className="license-requests__header">
                    {i18n('license_requests.page_title')}
                </h3>

                <div className="license-requests__list-header action">
                    <div className="license-requests__column license-requests__name">
                        {toggle}
                        <span className="license-requests__list-header-text">
                            {pluralize(requestCount, i18n('license_requests.requests'))}
                        </span>
                    </div>
                    <div className="license-requests__column license-requests__author">
                        {i18n('license_requests.header_title.author')}
                    </div>
                    <div className="license-requests__column license-requests__comment">
                        {i18n('license_requests.header_title.comment')}
                    </div>
                </div>
                {this._renderList()}

                <Loader visible={this.state.isLoading} />
            </div>
        );
    },
});

export default RequestsList;
