'use strict';

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

var _regenerator2 = _interopRequireDefault(_regenerator);

var _promise = require('babel-runtime/core-js/promise');

var _promise2 = _interopRequireDefault(_promise);

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

var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2);

var getFile = function () {
    var _ref = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee(params) {
        var github;
        return _regenerator2.default.wrap(function _callee$(_context) {
            while (1) {
                switch (_context.prev = _context.next) {
                    case 0:
                        github = connect();
                        return _context.abrupt('return', new _promise2.default(function (resolve, reject) {
                            try {
                                var response = github.repos.getContent(params);
                                return resolve(response);
                            } catch (err) {
                                return reject(err);
                            }
                        }));

                    case 2:
                    case 'end':
                        return _context.stop();
                }
            }
        }, _callee, this);
    }));

    return function getFile(_x) {
        return _ref.apply(this, arguments);
    };
}();

var updateGitHubPullRequest = function () {
    var _ref2 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee2(status, done) {
        return _regenerator2.default.wrap(function _callee2$(_context2) {
            while (1) {
                switch (_context2.prev = _context2.next) {
                    case 0:
                        if (!(status.context === 'COMMENT_ONLY')) {
                            _context2.next = 6;
                            break;
                        }

                        _context2.next = 3;
                        return addGitHubPullRequestComment(status, done);

                    case 3:
                        return _context2.abrupt('return', _context2.sent);

                    case 6:
                        _context2.next = 8;
                        return updateGitHubPullRequestStatus(status, done);

                    case 8:
                        return _context2.abrupt('return', _context2.sent);

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

    return function updateGitHubPullRequest(_x2, _x3) {
        return _ref2.apply(this, arguments);
    };
}();

/**
 * Create a Status Object to Send to GitHub
 * @param {object} eventData - Data from GitHub Event
 * @param {string} state - Current Task State (pending, passed, failed)
 * @param {string} context - Content Name to Display in GitHub
 * @param {string} description - Short Description to Display in GitHub
 * @param {string} url - Link to more detail
 *
 */


/**
 * export type ReposCreateStatusParams =
 & {
      owner: string;
      repo: string;
      sha: string;
      state: "pending"|"success"|"error"|"failure";
      target_url?: string;
      description?: string;
      context?: string;
    };
 */
var updateGitHubPullRequestStatus = function () {
    var _ref3 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee3(status, done) {
        var github;
        return _regenerator2.default.wrap(function _callee3$(_context3) {
            while (1) {
                switch (_context3.prev = _context3.next) {
                    case 0:
                        console.log('updating github for pull_request event ' + status.eventData.ghEventId);
                        //console.log(status);

                        _context3.prev = 1;
                        github = connect(status.context);
                        _context3.next = 5;
                        return github.repos.createStatus(status).then(function () {
                            done();
                        });

                    case 5:
                        return _context3.abrupt('return', _context3.sent);

                    case 8:
                        _context3.prev = 8;
                        _context3.t0 = _context3['catch'](1);

                        if (!(_context3.t0.message == 'OAuth2 authentication requires a token or key & secret to be set')) {
                            _context3.next = 12;
                            break;
                        }

                        throw _context3.t0;

                    case 12:
                        console.log('----- ERROR COMMUNICATING WITH GITHUB -----');
                        console.log(_context3.t0);
                        done();

                    case 15:
                    case 'end':
                        return _context3.stop();
                }
            }
        }, _callee3, this, [[1, 8]]);
    }));

    return function updateGitHubPullRequestStatus(_x4, _x5) {
        return _ref3.apply(this, arguments);
    };
}();

var addGitHubPullRequestComment = function () {
    var _ref4 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee4(status, done) {
        var github;
        return _regenerator2.default.wrap(function _callee4$(_context4) {
            while (1) {
                switch (_context4.prev = _context4.next) {
                    case 0:
                        console.log('add comment on pull_request completion ' + status.eventData.ghEventId);
                        /**
                         * declare type PullRequestsCreateReviewParams =
                         & {
                          owner: string;
                          repo: string;
                          number: number;
                          commit_id?: string;
                          body?: string;
                          event?: "APPROVE"|"REQUEST_CHANGES"|"COMMENT"|"PENDING";
                          comments?: string[];
                        };
                         */
                        _context4.prev = 1;
                        github = connect();
                        _context4.next = 5;
                        return github.pullRequests.createReview({
                            owner: status.owner,
                            repo: status.repo,
                            number: parseInt(status.number),
                            body: status.description,
                            event: 'COMMENT'
                        }).then(function () {
                            done();
                        });

                    case 5:
                        return _context4.abrupt('return', _context4.sent);

                    case 8:
                        _context4.prev = 8;
                        _context4.t0 = _context4['catch'](1);

                        console.log('----- ERROR COMMUNICATING WITH GITHUB -----');
                        console.log(_context4.t0);
                        done();

                    case 13:
                    case 'end':
                        return _context4.stop();
                }
            }
        }, _callee4, this, [[1, 8]]);
    }));

    return function addGitHubPullRequestComment(_x6, _x7) {
        return _ref4.apply(this, arguments);
    };
}();

var updateGitHubComment = function () {
    var _ref5 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee5(status, done) {
        return _regenerator2.default.wrap(function _callee5$(_context5) {
            while (1) {
                switch (_context5.prev = _context5.next) {
                    case 0:
                        console.log('updating github for comment event ' + status.eventData.ghEventId);

                        //let github = connect(status.context);
                        //return await github.repos.createStatus(status).then(() => {
                        done();
                        //});

                    case 2:
                    case 'end':
                        return _context5.stop();
                }
            }
        }, _callee5, this);
    }));

    return function updateGitHubComment(_x8, _x9) {
        return _ref5.apply(this, arguments);
    };
}();

var handleEventTaskResult = function () {
    var _ref6 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee6(message, done) {
        var status, updaterFunction;
        return _regenerator2.default.wrap(function _callee6$(_context6) {
            while (1) {
                switch (_context6.prev = _context6.next) {
                    case 0:
                        status = JSON.parse(message.Body);

                        console.log(status);

                        updaterFunction = githubUpdaters[status.eventData.ghEventType];

                        if (!updaterFunction) {
                            _context6.next = 7;
                            break;
                        }

                        return _context6.abrupt('return', updaterFunction(status, done));

                    case 7:
                        console.error('gitub updates for event type \'' + status.eventData.ghEventType + '\' are not supported yet.');
                        done();

                    case 9:
                    case 'end':
                        return _context6.stop();
                }
            }
        }, _callee6, this);
    }));

    return function handleEventTaskResult(_x10, _x11) {
        return _ref6.apply(this, arguments);
    };
}();

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

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

var json = require('format-json');
var GitHubApi = require('@octokit/rest');
var crypto = require('crypto');
var githubUpdaters = {
    pull_request: updateGitHubPullRequest,
    comment: updateGitHubComment
};

var ghEnforceValidSsl = process.env.NODE_TLS_REJECT_UNAUTHORIZED === 0;

function connect(context) {
    console.log('Connecting to GitHub');
    console.log('GitHub SSL Validation: ' + String(ghEnforceValidSsl));
    var githubOptions = {
        host: process.env.GTM_GITHUB_HOST || 'api.github.com',
        debug: process.env.GTM_GITHUB_DEBUG || false,
        timeout: parseInt(process.env.GTM_GITHUB_TIMEOUT) || 5000,
        pathPrefix: process.env.GTM_GITHUB_PATH_PREFIX || '',
        proxy: process.env.GTM_GITHUB_PROXY || '',
        rejectUnauthorized: ghEnforceValidSsl
    };

    console.log('Creating GitHub API Connection');
    var github = new GitHubApi(githubOptions);

    var token = process.env.GTM_GITHUB_TOKEN;
    if (context) {
        token = process.env['GTM_GITHUB_TOKEN_' + context.toUpperCase().replace('-', '_')] || process.env.GTM_GITHUB_TOKEN;
    }

    console.log('Authenticating with GitHub');
    github.authenticate({
        type: 'oauth',
        token: token
    });

    return github;
}

function signRequestBody(key, body) {
    return 'sha1=' + crypto.createHmac('sha1', key).update(body, 'utf-8').digest('hex');
}

function invalidHook(event) {
    var err = null;
    var errMsg = null;
    var token = process.env.GTM_GITHUB_WEBHOOK_SECRET;
    var headers = event.headers;
    var sig = headers['X-Hub-Signature'] || headers['x-hub-signature'];
    var githubEvent = headers['X-GitHub-Event'] || headers['x-github-event'];
    var id = headers['X-GitHub-Delivery'] || headers['x-github-delivery'];
    var calculatedSig = signRequestBody(token, event.body);

    var validators = [{
        name: 'github secret',
        check: typeof token !== 'string',
        msg: 'Must provide a \'GITHUB_WEBHOOK_SECRET\' env variable'
    }, {
        name: 'X-Hub-Signature',
        check: !sig,
        msg: 'No X-Hub-Signature found on request'
    }, {
        name: 'X-Github-Event',
        check: !githubEvent,
        msg: 'No X-Github-Event found on request'
    }, {
        name: 'X-Github-Delivery',
        check: !id,
        msg: 'No X-Github-Delivery found on request'
    }, {
        name: 'X-Hub-Signature signing',
        check: sig !== calculatedSig,
        msg: 'X-Hub-Signature incorrect. Github webhook token doesn\'t match'
    }];

    try {
        validators.forEach(function (v) {
            if (v.check) {
                errMsg = v.msg;
                throw new Error(errMsg);
            }
            console.log(v.name + ' is ok!');
        });
    } catch (e) {
        console.log(e.message);
        err = e;
    }

    return err;
}

function decodeFileResponse(fileResponse) {
    console.log(json.plain(fileResponse));
    var buff = new Buffer(fileResponse.data.content, 'base64');
    var content = JSON.parse(buff.toString('ascii'));

    return content;
}

function createPullRequestStatus(eventData, state, context, description, url) {
    return {
        owner: eventData.repository.owner.login || 'Default_Owner',
        repo: eventData.repository.name || 'Default_Repository',
        sha: eventData.pull_request.head.sha || 'Missing SHA',
        number: eventData.pull_request.number,
        state: state,
        target_url: url ? url : 'https://github.com/zotoio/github-task-manager',
        description: description,
        context: context,
        eventData: eventData
    };
}

module.exports = {
    connect: connect,
    signRequestBody: signRequestBody,
    invalidHook: invalidHook,
    decodeFileResponse: decodeFileResponse,
    getFile: getFile,
    handleEventTaskResult: handleEventTaskResult,
    updateGitHubPullRequestStatus: updateGitHubPullRequestStatus,
    createPullRequestStatus: createPullRequestStatus
};