import _ from 'lodash';
import PropTypes from 'prop-types';
import React from 'react';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import { ListDimensions } from 'constants/UI';
import StoreMixin from 'lib/StoreMixin';
import ScrollableList from 'ui/ScrollableList';

import Url from 'lib/Url';
import { i18n } from 'lib/i18n';
import Metrika from 'lib/metrika';

import UserActions from 'actions/User';
import DepartmentActions from 'actions/Department';

import ApplicationStore from 'stores/Application';
import DepartmentStore from 'stores/Departments';
import UserStore from 'stores/Users';
import ChunkStore from 'stores/Chunks';

import SectionListItem from 'components/SectionListItem';

const METRIKA_MAP = {
    user: 'Клик в пользователя',
    department: 'Клик в отдел',
};

const List = React.createClass({

    mixins: [StoreMixin, PureRenderMixin],

    getStoreState() {
        const { id } = this.props;

        // список отдела состоит из подотделов и пользователей;
        // когда список подотделов загружен полностью
        // (т.е. чанк списка подотделов отмечен как последний),
        // переключаемся на загрузку списка пользователей

        return {
            subdepartmentChunk: ChunkStore.get(`departments/parent_id=${id}`),
            userChunk: ChunkStore.get(`users/department_id=${id}`),
            key: this.hashCode(),
        };
    },

    componentDidMount() {
        this.subscribe([ApplicationStore, DepartmentStore, UserStore, ChunkStore]);
    },

    _handleItemClick(item) {
        Metrika.send('Структура', METRIKA_MAP[item.getType()]);
        Url.open(item.getUrl());
    },

    _getSubdepartments() {
        const chain = ApplicationStore.getObjectChain();
        let selectedFound = false;

        const items = this.state.subdepartmentChunk.getCollectedItems()
            .map(id => {
                const department = DepartmentStore.get(id);

                if (!department) {
                    return null;
                }

                const selected = !selectedFound &&
                    Boolean(_.find(chain, { id, type: 'department' }));

                // отмечаем, что выбранный элемент найден
                // выбранных элементов должно быть не больше одного
                if (selected) {
                    selectedFound = true;
                }

                const component = (
                    <SectionListItem
                        key={`department-${id}`}
                        ref={selected ? 'selectedDepartment' : null}
                        avatar={null}
                        primary
                        selected={selected}
                        item={department}
                        onClick={this._handleItemClick}
                    />
                );

                return { component, height: ListDimensions.DEPARTMENT_HEIGHT };
            })
            .filter(Boolean);

        if (items.length && String(this.props.id) !== '1') {
            items.unshift({
                component: (
                    <List.Title
                        key="subdepartments"
                        content={i18n('department.list.subdepartments')}
                    />
                ),
                height: ListDimensions.SECTION_TITLE_HEIGHT,
            });
        }

        return items;
    },

    _getUsers() {
        // не показываем пользователей в списке, даже если они уже есть в сторе,
        // до отметки о том, что все подотделы загружены
        if (!this.state.subdepartmentChunk.isLast()) {
            return [];
        }

        const chain = ApplicationStore.getObjectChain();
        const displayedUser = _.find(chain, { type: 'user' });
        let selectedFound = false;

        const items = this.state.userChunk.getCollectedItems()
            .map(id => {
                const user = UserStore.get(id);

                if (!user) {
                    return null;
                }

                const selected = !selectedFound &&
                    displayedUser && displayedUser.id === id;

                if (selected) {
                    selectedFound = true;
                }

                const component = (
                    <SectionListItem
                        key={`user-${id}`}
                        ref={selected ? 'selectedUser' : null}
                        selected={selected}
                        item={user}
                        onClick={this._handleItemClick}
                    />
                );

                return { component, height: ListDimensions.USER_HEIGHT };
            })
            .filter(Boolean);

        if (items.length) {
            items.unshift({
                component: (
                    <List.Title
                        key="users"
                        content={i18n('department.list.users')}
                    />
                ),
                height: ListDimensions.SECTION_TITLE_HEIGHT,
            });
        }

        return items;
    },

    _renderPlaceholder() {
        return (
            <div className="department-list-placeholder">
                {i18n('department.empty')}
            </div>
        );
    },

    _fetchItems() {
        const { userChunk, subdepartmentChunk } = this.state;

        if (subdepartmentChunk.isLast()) {
            return this._fetchUsers();
        }

        const request = this._fetchSubdepartments();

        if (request && !userChunk.getPage()) {
            request.then(() => {
                const shouldImmediatelyFetchUserChunk =
                    subdepartmentChunk.isLast() &&
                    subdepartmentChunk.getSize() < subdepartmentChunk.getMaxSize();

                if (shouldImmediatelyFetchUserChunk) {
                    this._fetchUsers();
                }
            });
        }
    },

    _fetchUsers() {
        const { userChunk, busy } = this.state;

        if (userChunk.isLast() || busy) {
            return;
        }

        this.setState({ busy: true });

        const requestOptions = {
            page: userChunk.getPage() + 1,
            department_id: this.props.id,
            ordering: 'name',
        };

        return UserActions.getList(requestOptions)
            .then(() => {
                this.setState({ busy: false });
            })
            .catch(() => {
                this.setState({ busy: false });
            });
    },

    _fetchSubdepartments() {
        const { subdepartmentChunk, busy } = this.state;

        if (subdepartmentChunk.isLast() || busy) {
            return;
        }

        this.setState({ busy: true });

        const requestOptions = {
            page: subdepartmentChunk.getPage() + 1,
            parent_id: this.props.id,
            ordering: 'name',
        };

        return DepartmentActions.getList(requestOptions)
            .then(() => {
                this.setState({ busy: false });
            })
            .catch(() => {
                this.setState({ busy: false });
            });
    },

    render() {
        const subdepartments = this._getSubdepartments();
        const users = this._getUsers();

        if (!subdepartments.length && !users.length) {
            return this._renderPlaceholder();
        }

        return (
            <ScrollableList
                className="department-list section-scrollpane"
                items={subdepartments.concat(users)}
                onBottomHit={this._fetchItems}
                busyBottom={this.state.busy}
                scrollTo={this.state.scrollTo}
                ref="list"
            />
        );
    },

});

List.Title = props => <h3 className="subsection-title">{props.content}</h3>;

List.propTypes = {
    id: PropTypes.string,
};

export default List;
