'use strict';

var _regenerator = require('babel-runtime/regenerator');

var _regenerator2 = _interopRequireDefault(_regenerator);

var _stringify = require('babel-runtime/core-js/json/stringify');

var _stringify2 = _interopRequireDefault(_stringify);

var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator');

var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2);

var listener = function () {
    var _ref = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee(event, context, callback) {
        var githubEvent, githubSignature, err, eventBody, response;
        return _regenerator2.default.wrap(function _callee$(_context) {
            while (1) {
                switch (_context.prev = _context.next) {
                    case 0:
                        console.log('hook call from ' + event.requestContext.identity.sourceIp + ' forwarded for ' + event.headers['X-Forwarded-For']);
                        githubEvent = event.headers['X-GitHub-Event'] || event.headers['x-github-event'];
                        githubSignature = event.headers['X-Hub-Signature'] || event.headers['x-hub-signature'];
                        _context.next = 5;
                        return githubUtils.invalidHook(event);

                    case 5:
                        err = _context.sent;

                        if (!err) {
                            _context.next = 8;
                            break;
                        }

                        return _context.abrupt('return', callback(err, {
                            statusCode: 401,
                            headers: { 'Content-Type': 'text/plain' },
                            body: err.message
                        }));

                    case 8:

                        // decode and parse event body
                        eventBody = decodeEventBody(event);

                        // blacklisted repos result in null error and 200 as this is a valid result

                        err = checkRepoBlacklisted(eventBody);

                        if (!err) {
                            _context.next = 12;
                            break;
                        }

                        return _context.abrupt('return', callback(null, {
                            statusCode: 200,
                            headers: { 'Content-Type': 'text/plain' },
                            body: err.message
                        }));

                    case 12:

                        /* eslint-disable */
                        console.log('---------------------------------');
                        console.log('Github-Event: "' + githubEvent + '"');
                        console.log('---------------------------------');
                        console.log('Payload', json.plain(eventBody));
                        /* eslint-enable */

                        response = void 0;
                        _context.prev = 17;
                        _context.next = 20;
                        return handleEvent(githubEvent, eventBody, githubSignature);

                    case 20:
                        response = {
                            statusCode: 200,
                            body: (0, _stringify2.default)({
                                input: event
                            })
                        };
                        _context.next = 27;
                        break;

                    case 23:
                        _context.prev = 23;
                        _context.t0 = _context['catch'](17);

                        err = _context.t0;
                        response = {
                            statusCode: 400,
                            headers: { 'Content-Type': 'text/plain' },
                            body: err.message
                        };

                    case 27:
                        return _context.abrupt('return', callback(err, response));

                    case 28:
                    case 'end':
                        return _context.stop();
                }
            }
        }, _callee, this, [[17, 23]]);
    }));

    return function listener(_x, _x2, _x3) {
        return _ref.apply(this, arguments);
    };
}();

var handleEvent = function () {
    var _ref2 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee2(type, body, signature) {
        var taskConfig, producer, pushForPullRequest, bodyString, ghEventId, ghAgentGroup, event;
        return _regenerator2.default.wrap(function _callee2$(_context2) {
            while (1) {
                switch (_context2.prev = _context2.next) {
                    case 0:
                        _context2.next = 2;
                        return getTaskConfig(type, body);

                    case 2:
                        taskConfig = _context2.sent;

                        if (taskConfig) {
                            _context2.next = 5;
                            break;
                        }

                        throw new Error('No task config for event type ' + type);

                    case 5:
                        console.log(json.plain(taskConfig));

                        // add event body to SQS
                        console.log('adding event to SQS: ' + process.env.SQS_PENDING_QUEUE_URL);

                        // create simple producer
                        producer = Producer.create({
                            queueUrl: process.env.SQS_PENDING_QUEUE_URL,
                            region: process.env.GTM_AWS_REGION
                        });
                        pushForPullRequest = false;
                        // if this is a push, determine whether related to an open pull_request

                        if (!(type === 'push' && body.commits.length > 0)) {
                            _context2.next = 13;
                            break;
                        }

                        _context2.next = 12;
                        return githubUtils.isCommitForPullRequest(body.commits[0].id);

                    case 12:
                        pushForPullRequest = _context2.sent;

                    case 13:
                        body.pushForPullRequest = pushForPullRequest;
                        bodyString = (0, _stringify2.default)(body);
                        ghEventId = UUID();
                        ghAgentGroup = taskConfig[type] && taskConfig[type].agentGroup ? taskConfig[type].agentGroup : 'default';
                        event = [{
                            id: ghEventId,
                            body: bodyString,
                            messageAttributes: {
                                ghEventId: { DataType: 'String', StringValue: ghEventId },
                                ghEventType: { DataType: 'String', StringValue: type },
                                ghTaskConfig: {
                                    DataType: 'String',
                                    StringValue: json.plain(taskConfig)
                                },
                                ghAgentGroup: { DataType: 'String', StringValue: ghAgentGroup }
                            }
                        }];
                        _context2.t0 = githubUtils;
                        _context2.next = 21;
                        return _KmsUtils2.default.getDecrypted(process.env.GTM_CRYPT_GITHUB_WEBHOOK_SECRET);

                    case 21:
                        _context2.t1 = _context2.sent;
                        _context2.t2 = (0, _stringify2.default)(event[0]);
                        signature = _context2.t0.signRequestBody.call(_context2.t0, _context2.t1, _context2.t2);


                        event[0].messageAttributes.ghEventSignature = {
                            DataType: 'String',
                            StringValue: signature
                        };

                        console.log('Outgoing event payload: ' + json.plain(event));

                        producer.send(event, function (err) {
                            if (err) console.log(err);
                        });

                        // set pull request status to pending for each task
                        if (type === 'pull_request') {
                            setPullRequestEventStatus(ghEventId, body);
                        }

                    case 28:
                    case 'end':
                        return _context2.stop();
                }
            }
        }, _callee2, this);
    }));

    return function handleEvent(_x4, _x5, _x6) {
        return _ref2.apply(this, arguments);
    };
}();

var getTaskConfig = function () {
    var _ref3 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee3(type, body) {
        var fileParams, fileResponse, taskConfig;
        return _regenerator2.default.wrap(function _callee3$(_context3) {
            while (1) {
                switch (_context3.prev = _context3.next) {
                    case 0:
                        fileParams = getFileParams(type, body);


                        console.log('file request params for ' + type + ' = ' + json.plain(fileParams));

                        _context3.next = 4;
                        return githubUtils.getFile(fileParams).catch(function (e) {
                            console.warn('Could not get taskConfig from GitHub: ' + json.plain(fileParams) + ', error is ' + json.plain(e));
                            return rp({
                                proxy: process.env.https_proxy || process.env.http_proxy || null,
                                json: true,
                                uri: process.env.GTM_TASK_CONFIG_DEFAULT_URL || 'https://raw.githubusercontent.com/zotoio/github-task-manager/master/.githubTaskManager.json'
                            }).then(function (config) {
                                config.pull_request.isDefaultConfig = true;
                                return {
                                    data: {
                                        content: Buffer.from((0, _stringify2.default)(config)).toString('base64')
                                    }
                                };
                            });
                        });

                    case 4:
                        fileResponse = _context3.sent;
                        taskConfig = githubUtils.decodeFileResponse(fileResponse);

                        if (!(!taskConfig[type] || !taskConfig[type].tasks || !taskConfig[type].tasks.length > 0)) {
                            _context3.next = 9;
                            break;
                        }

                        console.error('repository config not found for event type \'' + type + '\' in config ' + json.plain(taskConfig));
                        return _context3.abrupt('return', false);

                    case 9:

                        console.log('task config for ' + type + ' = ' + json.plain(taskConfig[type]));

                        return _context3.abrupt('return', taskConfig);

                    case 11:
                    case 'end':
                        return _context3.stop();
                }
            }
        }, _callee3, this);
    }));

    return function getTaskConfig(_x7, _x8) {
        return _ref3.apply(this, arguments);
    };
}();

require('source-map-support/register');

var _KmsUtils = require('./../../KmsUtils');

var _KmsUtils2 = _interopRequireDefault(_KmsUtils);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

process.on('unhandledRejection', function (reason, p) {
    console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
    // application specific logging, throwing an error, or other logic here
});

console.log('cold start');
require('source-map-support').install();
var rp = require('request-promise-native');
var json = require('format-json');
var UUID = require('uuid/v4');
var Producer = require('sqs-producer');
var githubUtils = require('../gtmGithubUtils.js');

function getFileParams(type, body) {
    switch (type) {
        case 'pull_request':
            return {
                owner: body.pull_request.head.repo.owner.login,
                repo: body.pull_request.head.repo.name,
                path: process.env.GTM_TASK_CONFIG_FILENAME || '.githubTaskManager.json',
                ref: body.pull_request.head.ref
            };
        case 'push':
            return {
                owner: body.repository.owner.login,
                repo: body.repository.name,
                path: process.env.GTM_TASK_CONFIG_FILENAME || '.githubTaskManager.json',
                ref: body.ref
            };
        default:
            return {
                owner: body.repository.owner.login,
                repo: body.repository.name,
                path: process.env.GTM_TASK_CONFIG_FILENAME || '.githubTaskManager.json',
                ref: 'master'
            };
    }
}

function decodeEventBody(event) {
    return JSON.parse(decodeURIComponent(event.body.replace(/\+/g, ' ')).replace('payload={', '{'));
}

function setPullRequestEventStatus(ghEventId, eventBody) {
    var url = void 0;
    if (process.env.GTM_ELASTIC_HOST && process.env.GTM_ELASTIC_PORT) {
        var baseUrl = process.env.GTM_BASE_URL || 'http://localhost:9091';
        url = baseUrl + '/metrics/log/gtm-' + ghEventId + '.txt';
    }

    var status = githubUtils.createPullRequestStatus(eventBody, 'pending', 'GitHub Task Manager', 'Queued ' + ghEventId, url);
    githubUtils.updateGitHubPullRequestStatus(status, function () {});
}

function checkRepoBlacklisted(body) {
    var repoName = body.pull_request ? body.pull_request.head.repo.name : body.repository.name;

    var blacklist = process.env.GTM_REPO_BLACKLIST ? process.env.GTM_REPO_BLACKLIST.split(',') : [];

    var blacklisted = false;
    if (blacklist && blacklist.length > 0) {
        blacklist.forEach(function (blacklistPattern) {
            if (!blacklisted) {
                var pattern = new RegExp(blacklistPattern.trim());
                if (pattern.test(repoName)) {
                    var msg = 'matched blacklist repo pattern \'' + blacklistPattern.trim() + '\' - skipping.';
                    console.log(msg);
                    blacklisted = new Error(msg);
                }
            }
        });
    }
    return blacklisted;
}

module.exports = {
    listener: listener,
    getTaskConfig: getTaskConfig,
    decodeEventBody: decodeEventBody,
    handleEvent: handleEvent
};