import Immutable from 'immutable';
import _ from 'lodash';

import extractMonogram from 'ui-components/lib/extractMonogram';
import generateColor from 'ui-components/lib/generateColor';
import generateAvatarImage from 'ui-components/lib/generateAvatarImage';
import AuthStore from 'stores/Auth';
import UserStore from 'stores/Users';
import DepartmentStore from 'stores/Departments';
import GroupStore from 'stores/Groups';
import Url from 'lib/Url';
import { formatDate } from 'lib/i18n';

const DEFAULTS = {
    created: undefined,
    description: undefined,
    author: undefined,
    email: undefined,
    label: undefined,
    id: undefined,
    members_count: undefined,
    members: undefined,
    admins: undefined,
    name: undefined,
    type: undefined,
};

function compareByName(a, b) {
    const aName = a.toSortableString();
    const bName = b.toSortableString();

    if (aName === bName) {
        return 0;
    }

    return aName > bName ? 1 : -1;
}

class Group extends Immutable.Record(DEFAULTS) {
    static PRIMARY_KEY = 'id';
    static TYPE_NAME = 'group';

    static create(data) {
        const nextData = _.pick(data, Object.keys(DEFAULTS));

        if (nextData.id !== undefined && nextData.id !== null) {
            nextData.id = String(nextData.id);
        }

        const existingGroup = GroupStore.get(nextData.id);

        if (existingGroup) {
            const existingMembers = existingGroup.get('members');
            const existingAdmins = existingGroup.get('admins');

            if (nextData.members === undefined && existingMembers) {
                nextData.members = existingMembers.toJS();
            }
            if (nextData.admins === undefined && existingAdmins) {
                nextData.admins = existingAdmins.toJS();
            }
        }

        return new Group(Immutable.fromJS(nextData));
    }

    /**
     * Возвращает аватар группы
     * @param {String} name
     * @returns {String}
     */
    static getAvatar(name) {
        const monogram = extractMonogram(name);
        const fill = generateColor(monogram);

        return generateAvatarImage(fill);
    }

    getId() {
        return this.get(Group.PRIMARY_KEY);
    }

    getType() {
        return Group.TYPE_NAME;
    }

    equals(x) {
        return (x instanceof Group) && x.getId() === this.getId();
    }

    getUrl() {
        return Url.getContextPath(`${this.getType()}s`, this.getId());
    }

    _getLocalized(path, locale) {
        locale = locale || AuthStore.getLocale();

        let value = this.getIn(path);

        if (value && typeof value !== 'string' && value.get) {
            value = value.get(locale);
        }

        return value;
    }

    getName(locale) {
        return this._getLocalized(['name'], locale || AuthStore.getLocale()) ||
            this._getLocalized(['name'], 'en') ||
            this._getLocalized(['name'], 'ru');
    }

    toSortableString(locale) {
        return (this.getName(locale) || '').toLowerCase();
    }

    getDescription(locale) {
        return this._getLocalized(['description'], locale || AuthStore.getLocale()) ||
            this._getLocalized(['description'], 'en') ||
            this._getLocalized(['description'], 'ru');
    }

    getAuthor() {
        return UserStore.get(this.get('author'));
    }

    getEmail() {
        return this.get('email');
    }

    getCreationDate() {
        return new Date(this.get('created'));
    }

    getReadableCreationDate() {
        return formatDate(this.get('created'));
    }

    getAdmins() {
        const admins = this.get('admins');

        return (admins ? admins.toJS() : [])
            .map(id => UserStore.get(id))
            .sort(compareByName);
    }

    getMembers() {
        const members = this.get('members');

        return (members ? members.toJS() : [])
            .map(item => {
                const { id, type } = item;

                switch (type) {
                    case 'user':
                        return UserStore.get(id);
                    case 'department':
                        return DepartmentStore.get(id);
                    case 'group':
                        return GroupStore.get(id);
                }
            })
            .filter(Boolean)
            .sort(compareByName);
    }

    getMemberCount() {
        return this.get('members_count');
    }

    getAvatar() {
        const monogram = extractMonogram(this.getName());
        const fill = generateColor(monogram);

        return generateAvatarImage(fill);
    }

    hasAllData() {
        return Boolean(this.get('members') && this.get('admins') && this.get('author'));
    }
}

export default Group;
