import _ from 'lodash';
import User from 'records/User';
import Department from 'records/Department';
import Group from 'records/Group';
import SearchItem from 'records/SearchItem';
import { i18n } from 'lib/i18n';

import AuthStore from 'stores/Auth';
import AuthService from 'services/auth';
import ConfigStore from 'stores/Config';

import departmentActions from 'actions/Department';

import template from 'client/lib/template';

export default {
    search,
    searchLicenses,
};

const typesMap = {
    user: 'people',
    department: 'departments',
    group: 'groups',
};

const defaultSuggestParams = {
    version: 2,
    types: [
        'people',
        'groups',
        'departments',
    ],
    limit: 3,
};

const recordMap = {
    people: User,
    groups: Group,
    departments: Department,
};

/**
 * Приводит данные, полученные с сервера в пригодный для саджеста вид
 * @protected
 * @param      {Object}   data
 * @param      {function} filter
 * @returns    {Object}
 */
function _parseResponse(data, filter) {
    const sections = [];

    for (const key in data) {
        let items = _.get(data, [key, 'result'], [])
            .map(value => {
                const record = recordMap[key];

                if (!record) {
                    return null;
                }

                let recordData = {
                    id: value.id,
                    title: value.title,
                    avatar: value.avatar_url || (record.getAvatar && record.getAvatar(value.title)),
                    description: value.description || '',
                    type: record.TYPE_NAME,
                };

                if (key === 'people') {
                    recordData = _.extend(recordData, {
                        description: `@${value.login}, ${value.department_name}`,
                        nickname: value.login,
                    });
                }

                return SearchItem.create(recordData);
            })
            .filter(Boolean);

        if (filter) {
            items = items.filter(filter);
        }

        if (items.length) {
            sections.push({
                sectionName: key === 'people' ? i18n('search.suggest.users') : i18n(`search.suggest.${key}`),
                suggestions: items.map(item => ({
                    value: '',
                    item,
                })),
            });
        }
    }

    return sections;
}

let licenseSearchCache = {};

function searchLicenses(suggestType, next) {
    let cacheKey = String(suggestType);

    if (licenseSearchCache[cacheKey]) {
        return next(null, licenseSearchCache[cacheKey]);
    }

    departmentActions.readRoot()
        .then(response => {
            const { departments, users, chunks } = response;
            const departmentChunk = chunks['departments/parent_id=1'] || {};
            const userChunk = chunks['users/department_id=1'] || {};

            let flatList = [];

            if (!suggestType || suggestType === 'department') {
                flatList.push(Department.create(departments[1]));

                if (departmentChunk.items) {
                    flatList = flatList.concat(
                        departmentChunk.items
                            .map(id => departments[Number(id)])
                            .filter(Boolean)
                            .map(Department.create)
                    );
                }
            }

            if ((!suggestType || suggestType === 'user') && userChunk.items) {
                flatList = flatList.concat(
                    userChunk.items
                        .map(id => users[Number(id)])
                        .filter(Boolean)
                        .map(User.create)
                );
            }

            licenseSearchCache[cacheKey] = [
                {
                    sectionName: null,
                    suggestions: flatList.map(item => ({
                        value: '',
                        item,
                    })),
                },
            ];

            next(null, licenseSearchCache[cacheKey]);
        });
}

/**
 * Выполняет поиск среди участников
 * @param   {Object}   params          объект для поиска
 * @param   {String}   params.text     строка для поиска
 * @param   {Number}   [params.limit]  лимит на результаты поиска
 * @param   {Array}    [params.types]  список типов по которым нужно искать
 * @param   {function} callback        колбэк для отображения саджеста
 * @param   {function} [filter]        фильтр результатов поиска
 * @returns {void}
 */
function search(params, callback, filter) {
    const requestParams = _.assign(
        {},
        defaultSuggestParams,
        {
            language: AuthStore.getLocale(),
            org_id: AuthStore.getOrganizationId(),
            request_id: String(Date.now()) + String(Math.floor(1e3 * Math.random())),
        },
        params
    );
    const url = generateSuggestUrl(requestParams);
    const fetchParams = {
        method: 'GET',
        mode: 'cors',
        cache: 'no-cache',
        credentials: 'include',
        headers: {
            Accept: 'application/json',
        },
    };

    fetch(url, fetchParams)
        .then(response => response.json())
        .then(data => {
            if (data.error_code) {
                const message = `Failed to execute 'fetch' to suggest: ${data.error_code}, ${data.error_message}`;
                const error = new Error(message);

                error.errorCode = data.error_code;

                throw error;
            }

            return _parseResponse(data, filter);
        })
        .then(data => callback(null, data))
        .catch(onSuggestRequestFail);
}

function generateSuggestUrl(params) {
    const queryParams = Object.keys(params).reduce((result, key) => {
        if (key === 'limit') {
            params.types.forEach(layer => {
                result[`${layer}.per_page`] = params.limit;
            });
        } else if (key === 'types') {
            result.layers = params.types.map(type => typesMap[type] || type).join(',');
        } else {
            result[key] = params[key];
        }

        return result;
    }, {});

    const query = Object.keys(queryParams)
        .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(queryParams[key])}`).join('&');

    return template.build(ConfigStore.get('api.app.suggest'), { query });
}

function onSuggestRequestFail(error) {
    const { errorCode } = error;

    switch (errorCode) {
        case 'ERROR_AUTH':
            AuthService.requireAuthorization();
            break;

        /* DIR-6642: Не редиректить на главную при ошибке REDIRECT_USER_ORGANIZATION от саджеста
        case 'REDIRECT_USER_ORGANIZATION':
            AuthService.startSession();
            break;
        */
    }
}
