import React from 'react';
import { Button, TextInput, Icon } from 'lego-on-react';
import { block } from 'bem-cn';
import SearchIcon from 'components/Icon/Search';

import directory from 'api2/directory';

import { PermissionStore, ServiceResourceRelationsStore } from 'lib2/stores';
import hasPermission from 'lib2/hasPermission';
import notify from 'lib2/notify';

import CheckListTable from 'components2/CheckListTable';
import AvatarUnit from 'components2/AvatarUnit';
import SpinOverlay from 'components2/SpinOverlay';
import Placeholder from 'components2/Placeholder';
import ResourceRelationsModal from 'components2/ResourceRelationsModal';

import { i18n } from 'i18n2';

import './index.css';

const b = block('resource-relations');

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

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

        this.state = {
            text: '',
            busy: false,
        };

        this._onFilterChange = this._onFilterChange.bind(this);
        this._filterRelations = this._filterRelations.bind(this);
        this._onPermissionStoreChange = this._onPermissionStoreChange.bind(this);
        this._onRelationStoreChange = this._onRelationStoreChange.bind(this);
        this._onCreateRelationsCancel = this._onCreateRelationsCancel.bind(this);
        this._onCreateRelationsConfirm = this._onCreateRelationsConfirm.bind(this);
        this._onCreateRelationButtonClick = this._onCreateRelationButtonClick.bind(this);
    }

    componentDidMount() {
        this._permissionStoreListener = PermissionStore.onChange(this._onPermissionStoreChange);
        this._relationStoreListener = ServiceResourceRelationsStore.onChange(this._onRelationStoreChange);

        this._update();
    }

    componentWillUnmount() {
        this._unmounted = true;
        this._relationStoreListener.remove();
        this._permissionStoreListener.remove();
    }

    _onRelationStoreChange() {
        const { serviceSlug, resourceId } = this.props;
        const relations = ServiceResourceRelationsStore.get([serviceSlug, resourceId, 'list']);

        this.setState({
            relations,
            filteredRelations: relations.filter(relation => this._filterRelations(relation, this.state.text)),
        });
    }

    _onPermissionStoreChange() {
        const { serviceSlug, resourceId } = this.props;

        this.setState({
            canChangeRelations: hasPermission('can_change_relations',
                { path: ['resource', serviceSlug, resourceId] }, true),
        });
    }

    _getText(key, params) {
        const { serviceSlug } = this.props;

        return i18n(`resource_page.${serviceSlug}.${key}`, params) ||
            i18n(`resource_page.default.${key}`, params);
    }

    _onFilterChange(text) {
        const { relations } = this.state;

        this.setState({
            text,
            filteredRelations: relations.filter(relation => this._filterRelations(relation, text)),
        });
    }

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

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

    _updateRelationList() {
        const { serviceSlug, resourceId } = this.props;

        return directory
            .send('GET', `/v11/resources/${encodeURIComponent(resourceId)}/relations/`, {
                query: {
                    service: serviceSlug,
                },
            })
            .then(({ ok, body }) => {
                if (ok) {
                    ServiceResourceRelationsStore.set([serviceSlug, resourceId, 'list'], body);
                }
            });
    }

    _filterRelations(relation, text) {
        if (!text) {
            return true;
        }

        const { object: { nickname = '', name: { last = '', middle = '', first = '' } } } = relation;

        if (nickname.toLowerCase().includes(text.toLowerCase())) {
            return true;
        }

        const filterData = [
            last,
            middle,
            first,
        ];

        return text
            .split(/\s+/)
            .every(word => filterData.some(namePart => namePart.toLowerCase().includes(word.toLowerCase())));
    }

    _onRemoveClick(id) {
        const { serviceSlug, onUpdate } = this.props;

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

        directory.send('DELETE', `/v11/relations/${serviceSlug}/${id}/`)
            .then(({ body, ok }) => {
                if (!ok) {
                    return notify(i18n(`backend_errors.relations.${body.code}`) ||
                        i18n('common.request_error'), 'error');
                }

                notify(this._getText('remove_relation_success'), 'success');

                if (onUpdate) {
                    onUpdate();
                }

                return this._updateRelationList();
            })
            .finally(() => {
                if (!this._unmounted) {
                    this.setState({
                        busy: false,
                    });
                }
            });
    }

    _renderHeader() {
        const { text } = this.state;
        const { canChangeRelations } = this.props;

        return (
            <div className={b('header')}>
                <div className={b('filter')}>
                    <TextInput
                        theme="normal"
                        size="m"
                        type="text"
                        pin="round-round"
                        placeholder={this._getText('filter')}
                        has-icon="true"
                        iconRight={(
                            <Icon
                                cls={b('search-icon')}
                                glyph="yes"
                            >
                                <SearchIcon />
                            </Icon>
                        )}
                        onChange={this._onFilterChange}
                        text={text}
                    />
                </div>
                {canChangeRelations &&
                <Button
                    theme="action"
                    size="m"
                    text={this._getText('create_relation')}
                    onClick={this._onCreateRelationButtonClick}
                />}
            </div>
        );
    }

    _onCreateRelationButtonClick() {
        this.setState({
            modalVisible: true,
        });
    }

    _onCreateRelationsConfirm() {
        return this._updateRelationList()
            .finally(() => {
                if (!this._unmounted) {
                    this.setState({
                        modalVisible: false,
                    });
                }
            });
    }

    _onCreateRelationsCancel() {
        this.setState({
            modalVisible: false,
        });
    }

    render() {
        const { serviceSlug, resourceId, cls, canChangeRelations, roles } = this.props;
        const { filteredRelations, relations, busy, modalVisible } = this.state;

        if (relations === undefined && busy) {
            return (
                <SpinOverlay
                    progress={busy}
                    size="m"
                    position="center"
                />
            );
        }

        if (!busy && (!relations || relations.length === 0)) {
            return (
                <div className={b({ slug: serviceSlug }).mix(cls)}>
                    <Placeholder
                        cls={b('empty')}
                        icon="no-relations"
                        title={this._getText('empty.relations_title')}
                        description={this._getText('empty.relations_description')}
                        action={canChangeRelations &&
                        <Button
                            theme="action"
                            size="m"
                            text={this._getText('create_relation')}
                            onClick={this._onCreateRelationButtonClick}
                        />}
                    />
                    <ResourceRelationsModal
                        roles={roles}
                        visible={modalVisible}
                        serviceSlug={serviceSlug}
                        resourceId={resourceId}
                        onCancel={this._onCreateRelationsCancel}
                        onConfirm={this._onCreateRelationsConfirm}
                        existingRelations={relations}
                    />
                </div>
            );
        }

        if (!busy && (!filteredRelations || filteredRelations.length === 0)) {
            return (
                <div className={b({ slug: serviceSlug }).mix(cls)}>
                    {this._renderHeader()}
                    <Placeholder
                        cls={b('empty')}
                        description={this._getText('empty.relations_search_title')}
                    />
                </div>
            );
        }

        return (
            <div className={b({ slug: serviceSlug }).mix(cls)}>
                {this._renderHeader()}
                <CheckListTable cls={b('table')}>
                    <Thead>
                        <Tr>
                            <Td role="user">
                                <span className={b('table-header-user')}>
                                    {this._getText('fields.user')}
                                </span>
                            </Td>
                            <Td role="subscriber">
                                <span className={b('table-header-role')}>
                                    {this._getText('fields.role')}
                                </span>
                            </Td>
                            <Td role="actions" />
                        </Tr>
                    </Thead>
                    <Tbody>
                        {filteredRelations.map(({ id, object, object_type: type, name, comment }) => (
                            <Tr key={`${type}-${object.id}`}>
                                <Td role="user">
                                    <AvatarUnit
                                        object={object}
                                        type={type}
                                    />
                                </Td>
                                <Td role="role">
                                    <div className={b('role')}>{roles && roles[name] || name}</div>
                                    {comment && <div className={b('comment')}>{comment}</div>}
                                </Td>
                                <Td role="actions">
                                    {canChangeRelations &&
                                    <Button
                                        theme="normal"
                                        size="m"
                                        text={i18n('resource_page.unsubscribe_one_item')}
                                        onClick={this._onRemoveClick.bind(this, id)}
                                    />}
                                </Td>
                            </Tr>
                        ))}
                    </Tbody>
                </CheckListTable>
                <SpinOverlay
                    progress={busy}
                    size="m"
                    position="center"
                    spinDelay={500}
                />
                <ResourceRelationsModal
                    roles={roles}
                    visible={modalVisible}
                    serviceSlug={serviceSlug}
                    resourceId={resourceId}
                    onCancel={this._onCreateRelationsCancel}
                    onConfirm={this._onCreateRelationsConfirm}
                    existingRelations={relations}
                />
            </div>
        );
    }
}
