import React from 'react';
import { Checkbox, Button, Icon } from 'lego-on-react';
import buildString from '@connect/string-placeholders';
import block from 'bem-cn';
import SpinOverlay from 'components2/SpinOverlay';
import CheckListTable from 'components2/CheckListTable';
import AvatarUnit from 'components2/AvatarUnit';
import TooltipBox from 'components/TooltipBox';
import QuestionIcon from 'components/Icon/Question';
import SelectionBar from 'components2/SelectionBar';
import SubscriptionModal from 'components2/SubscriptionModal';
import { ServiceSubscribersStore, PricingStore } from 'lib2/stores';
import canSubmitSubscriptions from 'lib2/canSubmitSubscriptions';
import toBillingUserForm from 'lib2/toBillingUserForm';
import getService from 'lib2/getService';
import getHelpUrl from 'lib2/getHelpUrl';
import hasPermission from 'lib2/hasPermission';
import toObjectKey from 'lib2/toObjectKey';
import toDataObject from 'lib2/toDataObject';
import onUrlHash from 'lib2/onUrlHash';
import notify from 'lib2/notify';
import directory from 'api2/directory';
import TrialStatus from 'const2/TrialStatus';
import { i18n, pluralize } from 'i18n2';

import './index.css';

const b = block('service-subscribers');

const { Thead, Tbody, Tr, Td } = CheckListTable;

export default class ServiceSubscribers extends React.PureComponent {
    constructor(props) {
        super(props);

        this.state = {
            busy: true,
            selectionMap: new Map(),
        };

        this._update = this._update.bind(this);

        this._toggleAll = this._toggleAll.bind(this);
        this._deselectAll = this._deselectAll.bind(this);

        this._addSubscription = this._addSubscription.bind(this);
        this._removeSubscription = this._removeSubscription.bind(this);
        this._removeSelectedSubscriptions = this._removeSelectedSubscriptions.bind(this);
        this._onCancel = this._onCancel.bind(this);
        this._onConfirm = this._onConfirm.bind(this);
    }

    componentDidMount() {
        this._hashListener = onUrlHash('#add-subscription', this._addSubscription);

        this._storeListeners = [
            ServiceSubscribersStore.onChange(this._update),
            PricingStore.onChange(this._update),
        ];

        this._init();
    }

    componentWillUnmount() {
        this._storeListeners.forEach(listener => listener.remove());
        this._unmounted = true;
        this._hashListener.remove();
    }

    componentDidUpdate(prevProps) {
        if (this.props.serviceSlug !== prevProps.serviceSlug) {
            this.setState({
                subscribers: undefined,
            });
            this._init();
        }
    }

    _init() {
        this.setState({
            busy: true,
        });

        if (this._unmounted) {
            return;
        }

        let { serviceSlug } = this.props;

        directory
            .send('GET', `/v11/subscription/services/${serviceSlug}/licenses/`)
            .then(({ ok, body }) => {
                if (ok) {
                    ServiceSubscribersStore.set([serviceSlug, 'list'], body);
                }
            })
            .finally(() => {
                if (!this._unmounted) {
                    this.setState({
                        busy: false,
                    });
                }
            });
    }

    _update() {
        let { serviceSlug } = this.props;

        this.setState({
            subscribers: ServiceSubscribersStore.get([serviceSlug, 'list']),
            pricingCount: PricingStore.get(['services', serviceSlug, 'users_count']),
        });
    }

    _toggle(object, type) {
        let { selectionMap } = this.state;
        let key = toObjectKey(object, type);

        if (selectionMap.has(key)) {
            selectionMap.delete(key);
        } else {
            selectionMap.set(key, toDataObject(object));
        }

        this.setState({
            selectionMap: new Map(selectionMap),
            allSelected: false,
        });
    }

    _toggleAll() {
        let { allSelected } = this.state;

        if (allSelected) {
            this._deselectAll();
        } else {
            this._selectAll();
        }

        this.setState({
            allSelected: !allSelected,
        });
    }

    _selectAll() {
        this.setState({
            selectionMap: new Map(
                this.state.subscribers
                    .map(({ object, object_type: type }) => [
                        toObjectKey(object, type),
                        toDataObject(object, type),
                    ])
            ),
        });
    }

    _deselectAll() {
        this.setState({
            selectionMap: new Map(),
            allSelected: false,
        });
    }

    _addSubscription() {
        let { serviceSlug } = this.props;

        canSubmitSubscriptions().then(allowed => {
            if (!allowed) {
                toBillingUserForm({
                    retpath: `/portal/services/${serviceSlug}#add-subscription`,
                    source: serviceSlug,
                });

                return;
            }

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

    _onConfirm() {
        let { onUpdate } = this.props;

        this.setState({ modalOpen: false });

        if (onUpdate) {
            onUpdate();
        }
    }

    _onCancel() {
        this.setState({ modalOpen: false });
    }

    _removeSubscription(object, type) {
        this._removeSubscriptions([toObjectKey(object, type)]);
    }

    _removeSelectedSubscriptions() {
        this._removeSubscriptions([...this.state.selectionMap.keys()]);
    }

    _removeSubscriptions(removedKeys) {
        let { serviceSlug, onUpdate } = this.props;
        let { subscribers } = this.state;

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

        directory
            .send('PUT', `/v11/subscription/services/${serviceSlug}/licenses/`, {
                body: JSON.stringify(
                    subscribers
                        .filter(item => !removedKeys.includes(toObjectKey(item)))
                        .map(toDataObject)
                ),
            })
            .then(({ ok, body }) => {
                if (!ok) {
                    let message = i18n(`backend_errors.${body.code}`) ||
                        pluralize(removedKeys.length, i18n('licenses.remove.error2'), '${objects}');

                    return notify(message, 'error');
                }

                notify(
                    pluralize(removedKeys.length, i18n('licenses.remove.success2'), '${objects}'),
                    'success'
                );

                ServiceSubscribersStore.set([serviceSlug, 'list'], body);

                if (onUpdate) {
                    onUpdate();
                }
            })
            .finally(() => {
                this.setState({
                    busy: false,
                });
            });

        this._deselectAll();
    }

    render() {
        let { serviceSlug, subscriberSearchType } = this.props;

        let {
            busy,
            subscribers,
            pricingCount,
            selectionMap,
            allSelected,
            modalOpen,
        } = this.state;

        let selectionCount = selectionMap.size;
        let editsAllowed = hasPermission('manage_licences');

        if (subscribers === undefined) {
            return (
                <div className={b()}>
                    <SpinOverlay
                        progress={busy}
                        size="m"
                        position="center"
                    />
                </div>
            );
        }

        if (!subscribers || subscribers.length === 0) {
            let { trial = {} } = getService(serviceSlug);
            let trialStatus = trial.status || TrialStatus.NOT_STARTED;

            return (
                <div className={b({ empty: true })}>
                    <h3 className={b('placeholder-title')}>
                        {i18n('licenses.empty_list.title')}
                    </h3>
                    <div className={b('placeholder-description')}>
                        {i18n(`licenses.${serviceSlug}.empty_list.description.trial_${trialStatus}`)}
                    </div>
                    {editsAllowed && (
                        <div className={b('placeholder-actions')}>
                            <Button
                                cls={b('button', { role: 'add-subscription' })}
                                text={i18n('licenses.subscribe_now')}
                                onClick={this._addSubscription}
                                size="m"
                                theme="action"
                            />
                        </div>
                    )}
                    {editsAllowed && (
                        <SubscriptionModal
                            serviceSlug={serviceSlug}
                            subscriberSearchType={subscriberSearchType}
                            existingSubscribers={subscribers}
                            onConfirm={this._onConfirm}
                            onCancel={this._onCancel}
                            visible={modalOpen}
                        />
                    )}
                </div>
            );
        }

        return (
            <div className={b()}>
                <div className={b('header')}>
                    <h3 className={b('title')}>
                        {i18n('licenses.users_with_subscription')}
                    </h3>
                    {editsAllowed &&
                    <Button
                        cls={b('button', { role: 'add-subscription' })}
                        text={i18n('licenses.subscribe_now')}
                        onClick={this._addSubscription}
                        size="m"
                        theme="action"
                    />}
                </div>
                <CheckListTable cls={b('table')}>
                    <Thead>
                        <Tr>
                            {editsAllowed &&
                            <Td role="checkbox">
                                <Checkbox
                                    cls={b('checkbox', { role: 'select-all' })}
                                    theme="normal"
                                    size="s"
                                    checked={allSelected}
                                    onChange={this._toggleAll}
                                />
                            </Td>}
                            <Td role="subscriber">
                                <div className={b('subscription-count')}>
                                    <span className={b('table-header-count')}>
                                        {pluralize(pricingCount, i18n('common.employees'))}
                                    </span>
                                    <TooltipBox
                                        htmlTip={i18n(`licenses.subscription_tooltip.${serviceSlug}`, {
                                            help_url: getHelpUrl(`ui.help.${serviceSlug}.licenses`),
                                        })}
                                        interaction="click"
                                        theme="normal"
                                        to="right"
                                        size="s"
                                    >
                                        <Icon
                                            cls={b('table-header-count-tip-icon')}
                                            glyph="yes"
                                        >
                                            <QuestionIcon />
                                        </Icon>
                                    </TooltipBox>
                                </div>
                            </Td>
                            <Td role="actions" />
                        </Tr>
                    </Thead>
                    <Tbody>
                        {subscribers.map(({ object, object_type: type }) => (
                            <Tr key={`${type}-${object.id}`}>
                                {editsAllowed &&
                                <Td role="checkbox">
                                    <Checkbox
                                        cls={b('checkbox', { role: 'select-item' })}
                                        theme="normal"
                                        size="s"
                                        checked={selectionMap.has(toObjectKey(object, type))}
                                        onChange={() => this._toggle(object, type)}
                                    />
                                </Td>}
                                <Td role="subscriber">
                                    <AvatarUnit
                                        object={object}
                                        type={type}
                                    />
                                </Td>
                                <Td role="actions">
                                    {editsAllowed &&
                                    <Button
                                        cls={b('button', { role: 'remove-item' })}
                                        theme="normal"
                                        size="m"
                                        text={i18n('licenses.unsubscribe_one_item')}
                                        onClick={() => this._removeSubscription(object, type)}
                                    />}
                                </Td>
                            </Tr>
                        ))}
                    </Tbody>
                </CheckListTable>
                {editsAllowed && (
                    <SelectionBar visible={selectionCount !== 0}>
                        <SelectionBar.Status>
                            {buildString(
                                pluralize(selectionCount, i18n('licenses.n_subscriptions_selected'), '${objects}'), {
                                    n_subscriptions: pluralize(selectionCount, i18n('balance.services.subscriptions')),
                                }
                            )}
                        </SelectionBar.Status>
                        <SelectionBar.Actions>
                            <Button
                                cls={b('button', { role: 'remove-selected' })}
                                text={pluralize(selectionCount, i18n('licenses.remove_subscription'), '${objects}')}
                                onClick={this._removeSelectedSubscriptions}
                                tone="grey"
                                view="default"
                                theme="action"
                                size="m"
                            />
                        </SelectionBar.Actions>
                        <SelectionBar.CloseButton
                            onClick={this._deselectAll}
                        />
                    </SelectionBar>
                )}
                {editsAllowed && (
                    <SubscriptionModal
                        serviceSlug={serviceSlug}
                        subscriberSearchType={subscriberSearchType}
                        existingSubscribers={subscribers}
                        onConfirm={this._onConfirm}
                        onCancel={this._onCancel}
                        visible={modalOpen}
                    />
                )}
                <SpinOverlay
                    progress={busy}
                    size="m"
                    position="center"
                    spinDelay={1500}
                />
            </div>
        );
    }
}
