/**
 * Мидлваря, отвечающая за авторизацию. next вызывается только если клиент авторизовался.
 */

const _ = require('lodash');
const responseContext = require('../lib/responseContext');
const sendHandledRequest = require('../lib/sendHandledRequest');

let config;

// список suid которые надо запросить у blackbox
const suids = [
    'subscription.suid.2', // почта
    'subscription.suid.55', // мобильная почта
    'subscription.suid.59', // диск
];

// Список полей, которые нужно запросить у blackbox
const dbfields = [
    'userinfo.lang.uid',
    'userinfo.country.uid',
    'userinfo.reg_date.uid',
    'hosts.db_id.2',
].concat(suids);

const UNAUTHORIZE_HTTP_CODE = 401;
const VALID_BLACKBOX_STATUSES = ['VALID', 'NEED_RESET'];

function getSessions(users) {
    const sessions = (users || []).map(userData => {
        const invalid = !userData || !userData.status ||
            VALID_BLACKBOX_STATUSES.indexOf(userData.status.value) === -1;

        if (invalid) {
            return;
        }

        const user = {
            id: userData.uid.value,
            login: userData.login,
            display_name: userData.display_name.name,
            avatar_id: _.get(userData.display_name, 'avatar.default'),
            locale: userData.dbfields['userinfo.lang.uid'],
            country: userData.dbfields['userinfo.country.uid'],
            org_id: userData.attributes['1017'],
            is_social: !userData.aliases['1'] && Boolean(userData.aliases['6']),
            is_light: !userData.aliases['1'] && Boolean(userData.aliases['5']),
            internal: config.app.maintainsInternalUsersOnly ||
                userData.attributes['1011'] === '1',
        };

        return user;
    }).filter(Boolean);

    return sessions;
}

function normalizeOutput(data) {
    // Формат ответа blackbox:
    // http://doc.yandex-team.ru/blackbox/reference/method-sessionid-response-json.xml

    let result = {};
    const status = _.get(data, 'status.value');

    // ошибка "OK" - это не ошибка (паспорт, чо)
    if (VALID_BLACKBOX_STATUSES.indexOf(status) === -1) {
        result.error = `invalid status on blackbox, status=${status}`;

        return result;
    }
    delete data.error;

    if (!data.default_uid) {
        result.error = 'нет поля "default_uid" в ответе паспорта';

        return result;
    }

    const sessions = getSessions(data.users);

    result = {
        karma: _.get(_.find(data.users, { id: data.default_uid }), 'karma.value'),
        state: {
            session: data.default_uid,
            reset_required: status === 'NEED_RESET',
        },
        session: _.clone(_.find(sessions, { id: data.default_uid })),
        sessions,
        user_ticket: data.user_ticket,
    };

    if (!result.session) {
        result.error = 'нет подходящего пользователя в массиве "users" ' +
            'в ответе паспорта';

        return result;
    }

    return result;
}

function requestBlackboxData(req, res, next) {
    let configCredentials;
    let configContext;

    if (!req.context) {
        req.context = {};
    }

    config = req.config;

    if (config.credentials instanceof Array) {
        configCredentials = config.credentials[config.credentialsIndex || 0];
    } else {
        configCredentials = config.credentials;
    }

    if (configCredentials) {
        // Обязательно клонировать, иначе один контекст будет для всех запросов!
        configContext = _.cloneDeep(configCredentials);
        req.context = _.extend(req.context, configContext);
        next();

        return;
    }

    if ((!req.cookies || !req.cookies.Session_id) && config.app.env !== 'ui-test') {
        req.context.auth = {
            errorCode: UNAUTHORIZE_HTTP_CODE,
            message: 'нет куки "Session_id"',
        };
        next();

        return;
    }

    const host = req.headers['x-forwarded-host'] || req.headers.host;

    return sendHandledRequest({
        method: 'get',
        url: config.api.blackbox,
        headers: {
            'X-Ya-Service-Ticket': _.get(req.context, 'tvm_tickets.blackbox'),
        },
        query: {
            method: 'sessionid',
            userip: responseContext.getUserIp(req),
            sessionid: req.cookies.Session_id,
            sslsessionid: req.cookies.sessionid2,
            emails: 'getall',
            host: host.split(':')[0],
            regname: 'yes',
            multisession: 'yes',
            get_user_ticket: 'yes',
            dbfields: dbfields.join(','),
            attributes: '1011,1017',
            aliases: '1,5,6',
            format: 'json',
        },
        source: req,
        label: 'read_blackbox',
    })
        .then(response => {
            const data = normalizeOutput(response);

            if (data.error) {
                req.context.auth = {
                    errorCode: UNAUTHORIZE_HTTP_CODE,
                    message: data.error,
                };
            } else {
                _.extend(req.context, data, {
                    auth: {
                        'x-uid': data.state.session,
                        'x-user-ip': responseContext.getUserIp(req),
                        'X-Ya-User-Ticket': data.user_ticket,
                        'X-Ya-Service-Ticket': _.get(req.context, 'tvm_tickets.directory_api'),
                    },
                });
            }
            next();
        })
        .catch(response => {
            if (response) {
                req.context.auth = {
                    errorCode: response.statusCode || 503,
                    message: 'ошибка при запросе паспорта',
                    instance: response,
                };
            } else {
                req.context.auth = {
                    errorCode: UNAUTHORIZE_HTTP_CODE,
                    message: 'request error',
                };
            }
            next();
        });
}

module.exports = requestBlackboxData;
