/**
 * Хранилище разрешенных действий
 */

import _ from 'lodash';
import Immutable from 'immutable';
import { ReduceStore } from 'flux/utils';
import { ActionTypes, Permissions } from 'constants/Common';
import dispatcher from 'dispatcher';
import ApplicationStore from 'stores/Application';
import AuthStore from 'stores/Auth';
import { toRecord } from 'records/util';

const USER_EDITING = [
    Permissions.EDIT_USER_INFO,
    Permissions.CHANGE_ALIAS,
    Permissions.CHANGE_USER_PASSWORD,
    Permissions.BLOCK_USER,
    Permissions.MAKE_ADMIN,
    Permissions.DISMISS_USER,
];

const DEPARTMENT_EDITING = [
    Permissions.EDIT_DEPARTMENT,
];

const ADDING_TO_DEPARTMENT = [
    Permissions.ADD_USERS,
    Permissions.ADD_DEPARTMENTS,
];

const GROUP_EDITING = [
    Permissions.EDIT_GROUP,
];

const ORGANIZATION_PROFILE_EDITING = [
    Permissions.DELETE_ORGANIZATION,
    Permissions.EDIT_ORGANIZATION,
];

const cache = {};

class PermissionStore extends ReduceStore {
    getInitialState() {
        return Immutable.fromJS(_.extend({
            global: [],
            local: [],
        }, _.get(window.ya, 'connect.initial.permissions')));
    }

    reduce(state, action) {
        const { data, type } = action;

        switch (type) {
            case ActionTypes.RECEIVE_MIXED_DATA:
                return this._receiveRawData(state, data);
        }

        return state;
    }

    _receiveRawData(state, data) {
        let nextState;
        const key = ApplicationStore.getStateId();

        if (data.permissions) {
            nextState = Immutable.fromJS(data.permissions);
            cache[key] = nextState;
        } else if (cache[key]) {
            nextState = cache[key];
        }

        return nextState || state;
    }

    /**
     * Проверяет наличие разрешения
     * @method  contains
     * @param   {String}   permission
     * @param   {Object?}  object
     * @param   {Boolean?} ignoreGlobal
     * @returns {Boolean}
     */
    contains(permission, object, ignoreGlobal) {
        const objectPath = object && (object.path || [object.getType(), object.getId()]);

        const path = object ? ['local', ...objectPath] : ['global'];
        let permissions = this._state.getIn(path);

        if (object && !permissions && !ignoreGlobal) {
            permissions = this._state.get('global');
        }

        return permissions ? permissions.includes(permission) : false;
    }

    /**
     * Проверяет разрешения на редактирование сервиса
     * @method  allowsServiceDataUpdate
     * @param   {String}  serviceSlug
     * @returns {Boolean}
     */
    allowsServiceDataUpdate(serviceSlug) {
        return this.contains(Permissions.UPDATE_SERVICE_DATA, toRecord({ type: 'service', id: serviceSlug }));
    }

    // заглушка для будущего реального права view_service_data
    allowsServiceDataView(serviceSlug) {
        return serviceSlug !== 'yandexsprav';
    }

    allowsPay() {
        return this.contains(Permissions.PAY);
    }

    allowsOrganizationEditing() {
        return this.contains(Permissions.EDIT_ORGANIZATION);
    }

    allowsManageServices() {
        return this.contains(Permissions.MANAGE_SERVICES);
    }

    /**
     * Проверяет разрешения на редактирование пользователя
     * @method  allowsUserEditing
     * @param   {Object?}  user
     * @returns {Boolean}
     */
    allowsUserEditing(user) {
        return _.some(USER_EDITING, permission => this.contains(permission, user));
    }

    /**
     * Проверяет разрешения на редактирование аватара пользователя
     * @method  allowsUserAvatarEditing
     * @param   {Object}  user
     * @returns {Boolean}
     */
    allowsUserAvatarEditing(user) {
        return this.contains(Permissions.CHANGE_AVATAR, user, true);
    }

    /**
     * Проверяет разрешения на редактирование всех полей пользователя
     * @method  allowsFullUserEditing
     * @param   {Object?}  user
     * @returns {Boolean}
     */
    allowsFullUserEditing(user) {
        return this.contains(Permissions.EDIT_USER, user);
    }

    /**
     * Проверяет разрешения на редактирование отдела
     * @method  allowsDepartmentEditing
     * @param   {Object?}  department
     * @returns {Boolean}
     */
    allowsDepartmentEditing(department) {
        const filter = permission => this.contains(permission, department);

        return _.some(DEPARTMENT_EDITING, filter) && AuthStore.getViewMode() === 'admin';
    }

    /**
     * Проверяет разрешения на добавление в отдел
     * @method  allowsAddingToDepartment
     * @param   {Object?}  department
     * @returns {Boolean}
     */
    allowsAddingToDepartment(department) {
        return _.some(ADDING_TO_DEPARTMENT, permission => this.contains(permission, department));
    }

    allowsDepartmentsAdd() {
        return this.contains(Permissions.ADD_DEPARTMENTS);
    }

    allowsGroupsAdd() {
        return this.contains(Permissions.ADD_GROUPS);
    }

    /**
     * Проверяет разрешения на редактирование команды
     * @method  allowsGroupEditing
     * @param   {Object?}  group
     * @returns {Boolean}
     */
    allowsGroupEditing(group) {
        return _.some(GROUP_EDITING, permission => this.contains(permission, group));
    }

    /**
     * Проверяет разрешение на редактирование настроек профиля
     * @method  allowsOrganizationProfileEditing
     * @returns {Boolean}
     */
    allowsOrganizationProfileEditing() {
        return _.some(ORGANIZATION_PROFILE_EDITING, permission => this.contains(permission));
    }

    /**
     * Проверяет разрешение на смену ролей для сотрудников
     * @method  allowsChangeRole
     * @returns {Boolean}
     */
    allowsChangeRole() {
        return this.contains(Permissions.CHANGE_ROLE);
    }

    /**
     * Проверяет разрешение на изминение dns записей
     * @method  allowsDNSEditing
     * @returns {Boolean}
     */
    allowsDNSEditing() {
        return this.contains(Permissions.EDIT_DNS);
    }

    /**
     * Проверяет разрешение на работу с доменами
     * @method  allowsDomainsEditing
     * @returns {Boolean}
     */
    allowsDomainsEditing() {
        return this.contains(Permissions.ADD_DOMAINS);
    }

    /**
     * Проверяет разрешение на редактирование структуры организации
     * @method  allowsOrganizationStructureEditing
     * @returns {Boolean}
     */
    allowsOrganizationStructureEditing() {
        return this.contains(Permissions.EDIT_DEPARTMENT);
    }

    allowsTrackerManagement() {
        return this.contains(Permissions.MANAGE_TRACKER);
    }

    allowsMailManagement() {
        return this.contains(Permissions.MANAGE_MAIL);
    }
}

export default window.ya.connect.PermissionStore = new PermissionStore(dispatcher);
