const url = require('url');
const path = require('path');
const crypto = require('crypto');
const _ = require('lodash');
const { ClementError } = require('@yandex-int/clement/lib/app-error');
const sanitizePath = require('../tests/hermione/helpers/sanitizePath');

class CacheFilePathTooLong extends ClementError {
    constructor(filePath) {
        super(`Длина пути до файла больше 260 ${filePath}`);
        this.statusCode = 400;
    }
}

const ignoreHeaders = [
    'etag',
    'x-dc',
    'x-qloud-router',
    'x-request-id',
    'x-response-time',
    'x-revision',
];

function isPassportUrl(requestUrl) {
    return requestUrl.includes('blackbox');
}

function filterPassportResponse(response) {
    response = JSON.parse(response);

    response = _.omit(response, ['age', 'connection_id', 'expires_in', 'ttl']);

    if (response && response.users) {
        response.users = response.users.map(user => _.omit(user, ['auth.password_verification_age']));
    }

    return JSON.stringify(response);
}

const cacheFilePath = {
    'cache-filepath'(ctx, next) {
        if (!ctx.cache.key || ctx.cache.filepath) {
            return next();
        }

        ctx.cache.filepath = sanitizePath(path.resolve(
            ctx.dumpsTestPath || ctx.cfg.cachePath,
            ctx.cfg.cacheName || ctx.sourceReq.host,
            String(ctx.sourceReq.path).slice(1)
        ));

        next();
    },
};

const cacheFileName = {
    'cache-filename'(ctx, next) {
        if (!ctx.cache.key || ctx.cache.filename) {
            return next();
        }

        const hash = crypto.createHash('sha256').update(ctx.cache.key).digest('hex');
        const method = String(ctx.sourceReq.method).toLowerCase();
        const filename = `${method}_${hash.slice(0, 20)}.json.gz`;
        const fullpath = path.join(ctx.cache.filepath, filename);

        if (fullpath.length > 260) {
            throw new CacheFilePathTooLong(fullpath);
        }

        ctx.cache.filename = filename;

        next();
    },
};

const sourceRequest = {
    'pre-data-fetch'(ctx, next) {
        const dumpsTestPath = _.get(ctx, 'sourceReq.query.dumps-test-path') ||
            _.get(ctx, 'req.parsedURL.query.dumps-test-path');

        if (dumpsTestPath) {
            ctx.dumpsTestPath = dumpsTestPath;
            if (ctx.sourceReq) {
                delete ctx.sourceReq.query['dumps-test-path'];
            }
        }

        next();
    },
};

const sourceResponse = {
    /**
     * Убирает служебные заголовки из данных в ответах ручек
     * @param {Object} ctx
     * @param {function} next
     */
    'cache-meta'(ctx, next) {
        try {
            const data = JSON.parse(ctx.cache.data);

            data.meta.sourceRes.headers = _.omit(data.meta.sourceRes.headers, ignoreHeaders);

            const urlObject = url.parse(data.meta.sourceRes.url);

            if (isPassportUrl(data.meta.sourceRes.url)) {
                data.data = filterPassportResponse(data.data);
            }

            // чистим урлы от всякого лишнего
            data.meta.sourceRes.url = urlObject.host + urlObject.pathname;
            data.meta.url = urlObject.pathname;

            ctx.cache.data = JSON.stringify(data);
        } catch (e) {
            console.error('cache-meta', e); // eslint-disable-line no-console
        }

        next();
    },
};

const cacheKey = {
    common: {
        'cache-key'(ctx, next) {
            if (!ctx.cache.key) {
                const { sourceReq } = ctx;

                ctx.cache.key = JSON.stringify({
                    method: sourceReq.method.toLowerCase(),
                    path: sourceReq.path,
                    query: _.omit(sourceReq.query || {}, [
                        'dumps-test-path',
                        'x-request-id',
                        'request_id', // для саджеста
                        'nickname', // потому что в тестах на создание пользователей, nickname рандомный
                    ]),
                    headers: _.pick(sourceReq.headers || {}, [
                        'x-uid',
                    ]),
                    body: {},
                });
            }

            next();
        },
    },

    passport: {
        'cache-key'(ctx, next) {
            if (!ctx.cache.key) {
                const { sourceReq } = ctx;

                ctx.cache.key = JSON.stringify({
                    method: sourceReq.method.toLowerCase(),
                    path: sourceReq.path,
                    query: _.omit(sourceReq.query || {}, [
                        'dumps-test-path',
                        'x-request-id',
                        'sessionid',
                        'sslsessionid',
                        'userip',
                        'host',
                    ]),
                });
            }

            next();
        },
    },

    auth: {
        'cache-key'(ctx, next) {
            if (!ctx.cache.key) {
                const { sourceReq } = ctx;
                const { __hash__ } = sourceReq.query;
                const query = __hash__ ? { __hash__ } : {};

                ctx.cache.key = JSON.stringify({
                    method: sourceReq.method.toLowerCase(),
                    path: sourceReq.path,
                    query,
                });
            }

            next();
        },
    },

};

module.exports = {
    sourceRequest,
    sourceResponse,
    cacheFileName,
    cacheFilePath,
    cacheKey,
};
