import _ from 'lodash';
import Immutable from 'immutable';
import log from 'services/log';
import Url from 'lib/Url';
import { i18n } from 'lib/i18n';
import ConfigStore from 'stores/Config';

function getErrors(response, errorNamespaces) {
    const ns = getErrorCodeNamespace(response);

    const errors = _.extend({},
        pickErrors(response, errorNamespaces),
        ns === 'org.dns' ? pickDnsErrors(response) : null,
        pickCaptchaErrors(response)
    );

    return new Immutable.Map(errors);
}

function pickErrors(response, errorNamespaces) {
    if (!response || !response.originalError) {
        return {};
    }

    const errors = {};

    const originalError = _.get(response.originalError, 'body');
    const errorList = originalError instanceof Array ? originalError : [originalError];

    if (!errorNamespaces) {
        errorNamespaces = [getErrorCodeNamespace(response)];
    }

    const messages = errorList
        .map(error => {
            if (error && error.code) {
                let message;

                for (let i = 0; i < errorNamespaces.length && !message; i++) {
                    message = i18n(`backend_errors.${errorNamespaces[i]}.${error.code}`, error.params);
                }

                return message || i18n(`backend_errors.${error.code}`, error.params);
            }
        })
        .filter(Boolean);

    if (messages.length === 0) {
        if (response.status) {
            messages.push(i18n('common.error.generic', { code: response.status }));
        } else {
            messages.push(i18n('common.error.unknown') || 'Unknown error');
        }
    }

    errors._common = messages;

    log.error(
        `Error ${response.status}: ${response.message}`,
        _.extend({ tag: 'backend-error' }, response.originalError.body)
    );

    return errors;
}

function pickDnsErrors(response) {
    let errors = _.get(response, 'originalError.body.errors', {});
    const commonError = _.get(response, 'originalError.body.message');

    if (commonError) {
        errors._common = commonError;
    }

    errors = _.omit(errors, '_schema');

    return convertMessagesToCodes(errors, 'backend_errors.dns');
}

function convertMessagesToCodes(errors, key) {
    if (!errors) {
        return errors;
    }

    if (typeof errors === 'string') {
        const name = errors
            .toLowerCase()
            .replace(/[\.!\?\(\)\{\}\[\]]/g, '')
            .replace(/\s+/g, '_');

        const errorKey = key ? `${key}.${name}` : name;

        return i18n(errorKey) || errorKey;
    }

    _.forEach(errors, (value, k) => {
        let nextKey = key;

        if (typeof k !== 'number') {
            nextKey = key ? `${key}.${k}` : k;
        }

        errors[k] = convertMessagesToCodes(value, nextKey);
    });

    return errors;
}

function pickCaptchaErrors(response) {
    if (!response || !response.code || response.code !== 'captcha_validation_error') {
        return;
    }

    return {
        captcha: i18n('common.captcha.error'),
    };
}

// вычисляем неймспейс кода ошибки из `url` запроса к API:
// `<app_root>/api/x` > `x.error_code`, `<app_root>/api/y/z` > `y.z.error_code`
function getErrorCodeNamespace(response) {
    let requestUrl = _.get(response, 'url', '');
    const apiPrefix = Url.getPath(ConfigStore.get('api.app.default'));

    if (requestUrl.indexOf(apiPrefix) === 0) {
        requestUrl = requestUrl.substring(apiPrefix.length);
    }

    return requestUrl.split('?')[0].split('/')
        .filter(Boolean)
        .map(component => component.replace(/\-/g, '_'))
        .join('.');
}

export default getErrors;
