import React from 'react';
import { Checkbox, Button, Link } 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 SelectionBar from 'components2/SelectionBar';
import { ServiceRequestsStore } from 'lib2/stores';
import toBillingUserForm from 'lib2/toBillingUserForm';
import canSubmitSubscriptions from 'lib2/canSubmitSubscriptions';
import hasPermission from 'lib2/hasPermission';
import toObjectKey from 'lib2/toObjectKey';
import toDataObject from 'lib2/toDataObject';
import getName from 'lib2/getName';
import notify from 'lib2/notify';
import directory from 'api2/directory';
import { i18n, pluralize, formatDate } from 'i18n2';

import './index.css';

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

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

const RequestFields = [
    'comment',
    'created_at',
    'service_slug',
    'department',
    'department.name',
    'department.members_count',
    'group',
    'group.name',
    'group.members_count',
    'author',
    'author.name',
    'user',
    'user.name',
    'user.position',
    'user.avatar_id',
];

const DAY = 86400000;

function toDisplayDate(date) {
    if (!date) {
        return '';
    }

    let d = new Date(date);

    if (Date.now() - d.getTime() < DAY) {
        return formatDate(d, 'time');
    }

    return formatDate(d);
}

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

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

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

        this._confirmSelected = this._confirmSelected.bind(this);
        this._denySelected = this._denySelected.bind(this);
    }

    componentDidMount() {
        this._storeListener = ServiceRequestsStore.onChange(() => this._update());

        this._init();
    }

    componentWillUnmount() {
        this._storeListener.remove();
    }

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

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

        let { serviceSlug } = this.props;

        directory
            .send('GET', `/v11/subscription/services/${serviceSlug}/licenses/request/`, {
                query: {
                    fields: RequestFields.join(','),
                    per_page: 100,
                },
            })
            .then(({ ok, body }) => {
                if (ok && body) {
                    ServiceRequestsStore.set([serviceSlug, 'list'], body.result);
                }
            })
            .finally(() => {
                this.setState({
                    busy: false,
                });
            });
    }

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

        this.setState({
            requests: ServiceRequestsStore.get([serviceSlug, 'list']),
        });
    }

    _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, type));
        }

        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.requests
                    .map(({ object, object_type: type }) => [
                        toObjectKey(object, type),
                        toDataObject(object, type),
                    ])
            ),
        });
    }

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

    _confirmSelected() {
        this._applyChanges([...this.state.selectionMap.values()], 'confirm');
    }

    _denySelected() {
        this._applyChanges([...this.state.selectionMap.values()], 'deny');
    }

    _applyChanges(items, action) {
        if (!Array.isArray(items)) {
            items = [items];
        }

        let { serviceSlug, onUpdate } = this.props;

        Promise.resolve(action === 'deny' || canSubmitSubscriptions()).then(allowed => {
            if (!allowed) {
                toBillingUserForm({
                    retpath: window.location.pathname,
                    source: serviceSlug,
                });

                return;
            }

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

            directory.send('POST', `/v11/subscription/services/${serviceSlug}/licenses/request/${action}/`, {
                body: JSON.stringify(items.map(toDataObject)),
            })
                .then(({ ok, body }) => {
                    if (body && body.code === 'cancelByUser') {
                        return;
                    }

                    if (!ok) {
                        return notify(
                            pluralize(items.length, i18n(`license_requests.${action}.error2`), '${objects}'),
                            'error'
                        );
                    }

                    notify(
                        pluralize(items.length, i18n(`license_requests.${action}.success2`), '${objects}'),
                        'success'
                    );

                    if (body) {
                        ServiceRequestsStore.set([serviceSlug, 'list'], body.result);
                    }

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

        this._deselectAll();
    }

    render() {
        let {
            busy,
            requests,
            selectionMap,
            allSelected,
        } = this.state;

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

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

        if (!requests || requests.length === 0) {
            return (
                <div className={b({ empty: true })}>
                    <h3 className={b('placeholder-title')}>
                        {i18n('license_requests.empty.title')}
                    </h3>
                    <div className={b('placeholder-description')}>
                        {i18n('license_requests.empty.description')}
                    </div>
                </div>
            );
        }

        return (
            <div className={b()}>
                <div className={b('header')}>
                    <h3 className={b('title')}>
                        {i18n('license_requests.page_title')}
                    </h3>
                </div>
                <CheckListTable cls={b('table')}>
                    <Thead>
                        <Tr>
                            {editsAllowed &&
                            <Td role="checkbox">
                                <Checkbox
                                    theme="normal"
                                    size="s"
                                    checked={allSelected}
                                    onChange={this._toggleAll}
                                />
                            </Td>}
                            <Td role="request">
                                {pluralize(requests.length, i18n('license_requests.requests'))}
                            </Td>
                            <Td role="author">
                                {i18n('license_requests.header_title.author')}
                            </Td>
                            <Td role="comment">
                                {i18n('license_requests.header_title.comment')}
                            </Td>
                            <Td role="actions" />
                        </Tr>
                    </Thead>
                    <Tbody>
                        {requests.map(({
                            object,
                            object_type: type,
                            author,
                            created_at: date,
                            comment,
                        }) => (
                            <Tr key={`${type}-${object.id}`}>
                                {editsAllowed &&
                                <Td role="checkbox">
                                    <Checkbox
                                        theme="normal"
                                        size="s"
                                        checked={selectionMap.has(toObjectKey(object, type))}
                                        onChange={() => this._toggle(object, type)}
                                    />
                                </Td>}
                                <Td role="request">
                                    <AvatarUnit
                                        object={object}
                                        type={type}
                                    />
                                </Td>
                                <Td role="author">
                                    <div className={b('request-author')}>
                                        {getName(author)}
                                    </div>
                                    <div className={b('request-date')}>
                                        {toDisplayDate(date)}
                                    </div>
                                </Td>
                                <Td role="comment">
                                    <span className={b('request-comment')}>
                                        {comment}
                                    </span>
                                </Td>
                                <Td role="actions">
                                    {editsAllowed &&
                                    <Button
                                        theme="normal"
                                        size="m"
                                        text={i18n('license_requests.action_text.deny')}
                                        onClick={() => this._applyChanges({ object, type }, 'deny')}
                                    />}
                                    {editsAllowed &&
                                    <Button
                                        theme="action"
                                        size="m"
                                        text={i18n('license_requests.action_text.confirm')}
                                        onClick={() => this._applyChanges({ object, type }, 'confirm')}
                                    />}
                                </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: 'confirm-selected' })}
                                text={pluralize(
                                    selectionCount,
                                    i18n('license_requests.confirm_selected'),
                                    '${objects}'
                                )}
                                onClick={this._confirmSelected}
                                tone="grey"
                                view="default"
                                theme="action"
                                size="m"
                            />
                            <Link
                                cls={b('button', { role: 'deny-selected' })}
                                text={pluralize(selectionCount, i18n('license_requests.deny_selected'), '${objects}')}
                                onClick={this._denySelected}
                                theme="white"
                                size="m"
                            />
                        </SelectionBar.Actions>
                        <SelectionBar.CloseButton
                            onClick={this._deselectAll}
                        />
                    </SelectionBar>
                )}
                <SpinOverlay
                    progress={busy}
                    size="m"
                    position="center"
                    spinDelay={1500}
                />
            </div>
        );
    }
}
