'use strict';

Object.defineProperty(exports, "__esModule", {
    value: true
});
exports.EventHandlerPullRequest = undefined;

var _keys = require('babel-runtime/core-js/object/keys');

var _keys2 = _interopRequireDefault(_keys);

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

var _promise2 = _interopRequireDefault(_promise);

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

var _regenerator2 = _interopRequireDefault(_regenerator);

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

var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2);

var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of');

var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);

var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');

var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);

var _createClass2 = require('babel-runtime/helpers/createClass');

var _createClass3 = _interopRequireDefault(_createClass2);

var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');

var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);

var _inherits2 = require('babel-runtime/helpers/inherits');

var _inherits3 = _interopRequireDefault(_inherits2);

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

var _EventHandler2 = require('../agent/EventHandler');

var _Executor = require('../agent/Executor');

var _AgentUtils = require('../agent/AgentUtils');

var _formatJson = require('format-json');

var _formatJson2 = _interopRequireDefault(_formatJson);

var _lodash = require('lodash');

var _lodash2 = _interopRequireDefault(_lodash);

var _fs = require('fs');

var _fs2 = _interopRequireDefault(_fs);

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

var EventHandlerPullRequest = exports.EventHandlerPullRequest = function (_EventHandler) {
    (0, _inherits3.default)(EventHandlerPullRequest, _EventHandler);

    function EventHandlerPullRequest() {
        (0, _classCallCheck3.default)(this, EventHandlerPullRequest);
        return (0, _possibleConstructorReturn3.default)(this, (EventHandlerPullRequest.__proto__ || (0, _getPrototypeOf2.default)(EventHandlerPullRequest)).apply(this, arguments));
    }

    (0, _createClass3.default)(EventHandlerPullRequest, [{
        key: 'handleEvent',
        value: function () {
            var _ref = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee() {
                var _this2 = this;

                var log, startTime, supportedActions;
                return _regenerator2.default.wrap(function _callee$(_context) {
                    while (1) {
                        switch (_context.prev = _context.next) {
                            case 0:
                                log = this.log;
                                startTime = new Date().getTime();
                                supportedActions = ['opened', 'synchronize'];

                                if (supportedActions.includes(this.eventData.action)) {
                                    _context.next = 6;
                                    break;
                                }

                                log.error('Unsupported Action: \'' + this.eventData.action + '\'');
                                return _context.abrupt('return');

                            case 6:

                                log.info({
                                    resultType: 'START',
                                    eventType: 'pull_request',
                                    repo: this.eventData.repository.full_name,
                                    url: this.eventData.pull_request.html_url,
                                    pullTitle: this.eventData.pull_request.title,
                                    pullNumber: this.eventData.number,
                                    sha: this.eventData.pull_request.head.sha,
                                    eventUser: this.eventData.pull_request.user.login
                                });

                                log.info('---------------------------------');
                                log.info('Repository Name: ' + this.eventData.repository.full_name);
                                log.info('Pull Request: ' + this.eventData.pull_request.number);
                                log.info('---------------------------------');

                                return _context.abrupt('return', this.handleTasks(this, this).then(function () {
                                    return _this2.addPullRequestSummaryComment(_this2).then(function (event) {
                                        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-' + event.eventId + '.txt';
                                        }
                                        var status = event.failed ? 'failure' : 'success';
                                        var eventStatus = _AgentUtils.AgentUtils.createPullRequestStatus(_this2.eventData, status, 'GitHub Task Manager', 'Completed ' + event.eventId, url);

                                        _AgentUtils.AgentUtils.postResultsAndTrigger(eventStatus, 'Executing event: ' + event.eventId);
                                        var endTime = new Date().getTime();
                                        var duration = endTime - startTime;
                                        log.info({
                                            resultType: 'EVENT',
                                            eventType: 'pull_request',
                                            repo: event.eventData.repository.full_name,
                                            url: event.eventData.pull_request.html_url,
                                            duration: duration,
                                            failed: event.failed || false
                                        });
                                    });
                                }));

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

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

            return handleEvent;
        }()

        /**
         * 1. set all PR status to 'pending'
         * 2. wait a few seconds to allow SQS events to set status.  update when FIFO SQS available
         * 3. process all tasks and update each PR check status
         *
         * @param event - the current event being processed
         * @param parent - current task, which is also the parent of the 'tasks' array if defined
         * @returns {Promise<T>}
         */

    }, {
        key: 'handleTasks',
        value: function () {
            var _ref2 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee2(event, parent) {
                var _this3 = this;

                return _regenerator2.default.wrap(function _callee2$(_context2) {
                    while (1) {
                        switch (_context2.prev = _context2.next) {
                            case 0:
                                return _context2.abrupt('return', this.setIntialTaskState(event, parent).then(function () {
                                    return _AgentUtils.AgentUtils.timeout(10000).then(function () {
                                        return _this3.processTasks(event, parent);
                                    });
                                }));

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

            function handleTasks(_x, _x2) {
                return _ref2.apply(this, arguments);
            }

            return handleTasks;
        }()
    }, {
        key: 'setIntialTaskState',
        value: function () {
            var _ref3 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee4(event, parent) {
                var _this4 = this;

                var promises, log, url, baseUrl, eventStatus, warningPath, warning;
                return _regenerator2.default.wrap(function _callee4$(_context4) {
                    while (1) {
                        switch (_context4.prev = _context4.next) {
                            case 0:
                                promises = [];
                                log = this.log;
                                url = void 0;

                                if (process.env.GTM_ELASTIC_HOST && process.env.GTM_ELASTIC_PORT) {
                                    baseUrl = process.env.GTM_BASE_URL || 'http://localhost:9091';

                                    url = baseUrl + '/metrics/log/gtm-' + event.eventId + '.txt';
                                }

                                eventStatus = _AgentUtils.AgentUtils.createPullRequestStatus(this.eventData, 'pending', 'GitHub Task Manager', 'Executing ' + event.eventId, url);


                                promises.push(_AgentUtils.AgentUtils.postResultsAndTrigger(eventStatus, 'Executing event: ' + event.eventId, log));

                                if (!event.taskConfig.pull_request.isDefaultConfig) {
                                    _context4.next = 11;
                                    break;
                                }

                                warningPath = process.env.GTM_TASK_CONFIG_DEFAULT_MESSAGE_PATH || __dirname + '/PullRequestDefaultConfigWarning.md';
                                warning = _fs2.default.readFileSync(warningPath, 'utf-8');
                                _context4.next = 11;
                                return this.addPullRequestComment(event, warning, null);

                            case 11:

                                if (parent.tasks) {
                                    parent.tasks.forEach(function () {
                                        var _ref4 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee3(task) {
                                            var initialState, initialDesc, eventContext, status;
                                            return _regenerator2.default.wrap(function _callee3$(_context3) {
                                                while (1) {
                                                    switch (_context3.prev = _context3.next) {
                                                        case 0:
                                                            if (!task.disabled) {
                                                                _context3.next = 3;
                                                                break;
                                                            }

                                                            log.warn('skipping disabled task ' + event.eventType + ' => ' + task.executor + ':' + task.context);
                                                            return _context3.abrupt('return');

                                                        case 3:

                                                            task.options = _AgentUtils.AgentUtils.applyTransforms(_AgentUtils.AgentUtils.templateReplace(_AgentUtils.AgentUtils.createBasicTemplate(_this4.eventData, parent, log), task.options, log));

                                                            initialState = 'pending';
                                                            initialDesc = 'Task Execution in Progress';


                                                            if (!_Executor.Executor.isRegistered(task.executor)) {
                                                                initialState = 'error';
                                                                initialDesc = 'Unknown Executor: ' + task.executor;
                                                            }

                                                            if (!parent.hash) {
                                                                log.info('No Parent Hash Found. Creating Child Hash');
                                                                task.hash = _AgentUtils.AgentUtils.createMd5Hash(task);
                                                            } else {
                                                                log.info('Parent Hash Found. Appending to Child Hash');
                                                                task.hash = _AgentUtils.AgentUtils.createMd5Hash(task, parent.hash);
                                                            }

                                                            eventContext = task.executor + ': ' + task.context + ' (' + task.hash + ')';
                                                            status = _AgentUtils.AgentUtils.createPullRequestStatus(event.eventData, initialState, eventContext, initialDesc, 'https://github.com' // fails if not an https url
                                                            );


                                                            promises.push(_AgentUtils.AgentUtils.postResultsAndTrigger(status, 'Pending for ' + event.eventType + ' => ' + task.executor + ':' + task.context + ' - Event ID: ' + event.eventId, log).then(function () {
                                                                log.info(task);
                                                                log.info('-----------------------------');
                                                            }));

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

                                        return function (_x5) {
                                            return _ref4.apply(this, arguments);
                                        };
                                    }());
                                }

                                return _context4.abrupt('return', _promise2.default.all(promises));

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

            function setIntialTaskState(_x3, _x4) {
                return _ref3.apply(this, arguments);
            }

            return setIntialTaskState;
        }()
    }, {
        key: 'processTasks',
        value: function () {
            var _ref5 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee6(event, parent) {
                var _this5 = this;

                var promises, log;
                return _regenerator2.default.wrap(function _callee6$(_context6) {
                    while (1) {
                        switch (_context6.prev = _context6.next) {
                            case 0:
                                promises = [];
                                log = this.log;


                                if (parent.tasks) {
                                    parent.tasks.forEach(function () {
                                        var _ref6 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee5(task) {
                                            var eventContext, executor, status, taskPromise, startTime;
                                            return _regenerator2.default.wrap(function _callee5$(_context5) {
                                                while (1) {
                                                    switch (_context5.prev = _context5.next) {
                                                        case 0:
                                                            if (!task.disabled) {
                                                                _context5.next = 3;
                                                                break;
                                                            }

                                                            log.warn('task disabled: ' + task.executor + ': ' + task.context);
                                                            return _context5.abrupt('return');

                                                        case 3:
                                                            if (_Executor.Executor.isRegistered(task.executor)) {
                                                                _context5.next = 6;
                                                                break;
                                                            }

                                                            log.error('executor not registered: ' + task.executor + ': ' + task.context);
                                                            return _context5.abrupt('return');

                                                        case 6:
                                                            eventContext = task.executor + ': ' + task.context + ' (' + task.hash + ')';


                                                            log.info('=================================');
                                                            log.info('Creating Executor for Task: ' + task.executor + ':' + task.context);
                                                            executor = _Executor.Executor.create(task.executor, event.eventData, event.log);
                                                            status = void 0;
                                                            taskPromise = void 0;
                                                            startTime = new Date().getTime();


                                                            try {
                                                                taskPromise = executor.executeTask(task).then(function (task) {
                                                                    if (task.results === 'NO_MATCHING_TASK') {
                                                                        status = _AgentUtils.AgentUtils.createPullRequestStatus(event.eventData, 'error', eventContext, 'Unknown Task Type: ' + task.context, 'https://kuro.neko.ac');
                                                                    } else {
                                                                        var defaultResultMessage = task.results.passed ? 'Task Completed Successfully' : 'Task Completed with Errors';
                                                                        var taskResultMessage = task.results.message || defaultResultMessage;
                                                                        status = _AgentUtils.AgentUtils.createPullRequestStatus(event.eventData, task.results.passed ? 'success' : 'error', eventContext, taskResultMessage, task.results.url);
                                                                    }
                                                                    return status;
                                                                }).then(function (status) {
                                                                    _this5.handleTaskResult(event, task, log, startTime);

                                                                    return _AgentUtils.AgentUtils.postResultsAndTrigger(status, 'Result \'' + status.state + '\' for ' + event.eventType + ' => ' + task.executor + ':' + task.context + ' - Event ID: ' + event.eventId, log);
                                                                }).then(function () {
                                                                    return task;
                                                                }).catch(function (e) {
                                                                    log.error(e);

                                                                    if (!task.results) {
                                                                        task.results = {
                                                                            passed: false,
                                                                            url: 'https://github.com/zotoio/github-task-manager',
                                                                            message: e.message
                                                                        };
                                                                    }

                                                                    status = _AgentUtils.AgentUtils.createPullRequestStatus(event.eventData, 'error', eventContext, 'Task execution failure', task.results.url);

                                                                    _this5.handleTaskResult(event, task, log, startTime);

                                                                    return _AgentUtils.AgentUtils.postResultsAndTrigger(status, 'Result \'error\' for ' + event.eventType + ' => ' + task.executor + ':' + task.context + ' - Event ID: ' + event.eventId, log).then(function () {
                                                                        var taskMasked = _lodash2.default.cloneDeep(task);
                                                                        if (taskMasked.options && taskMasked.options.env) {
                                                                            (0, _keys2.default)(taskMasked.options.env).forEach(function (key) {
                                                                                if (new RegExp('LOGIN|OAUTH|KEY|TOKEN|SECRET|PASSW').test(key)) {
                                                                                    taskMasked.options.env[key] = _AgentUtils.AgentUtils.maskString(taskMasked.options.env[key]);
                                                                                }
                                                                            });
                                                                            taskMasked.options.env.GIT_CLONE = event.eventData.repository.clone_url;
                                                                        }

                                                                        var commentBody = '### Task failed during event ' + event.eventId + '\n\'' + task.executor + ': ' + task.context + '\', any subtasks have been skipped. Config: \n```json\n' + _formatJson2.default.plain(taskMasked) + '\n```';
                                                                        return _this5.addPullRequestComment(event, commentBody, task);
                                                                    }).then(function () {
                                                                        return task;
                                                                    });
                                                                });
                                                            } catch (e) {
                                                                log.error(e);

                                                                _this5.handleTaskResult(event, task, log, startTime);

                                                                taskPromise = _promise2.default.reject(e.message);
                                                            }

                                                            promises.push(taskPromise);

                                                        case 15:
                                                        case 'end':
                                                            return _context5.stop();
                                                    }
                                                }
                                            }, _callee5, _this5);
                                        }));

                                        return function (_x8) {
                                            return _ref6.apply(this, arguments);
                                        };
                                    }());
                                }

                                return _context6.abrupt('return', this.handleSubtasks(event, promises));

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

            function processTasks(_x6, _x7) {
                return _ref5.apply(this, arguments);
            }

            return processTasks;
        }()

        /**
         * Deal with subtasks of each promise from current task array
         *
         * @param event - current event being processed
         * @param promises from current task array
         * @returns {Promise<[any]>} promises for subtasks resolved via Promise.all
         */

    }, {
        key: 'handleSubtasks',
        value: function handleSubtasks(event, promises) {
            var _this6 = this;

            var subtaskPromises = [];
            var log = this.log;

            promises.forEach(function () {
                var _ref7 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee8(promise) {
                    return _regenerator2.default.wrap(function _callee8$(_context8) {
                        while (1) {
                            switch (_context8.prev = _context8.next) {
                                case 0:
                                    // for each sibling task
                                    subtaskPromises.push(
                                    //..wait for task to complete
                                    promise.then(function () {
                                        var _ref8 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee7(task) {
                                            return _regenerator2.default.wrap(function _callee7$(_context7) {
                                                while (1) {
                                                    switch (_context7.prev = _context7.next) {
                                                        case 0:
                                                            if (!(!task.disabled && task.tasks)) {
                                                                _context7.next = 7;
                                                                break;
                                                            }

                                                            //..and the task failed, skip subtasks
                                                            log.info(task.executor + ': ' + task.context + ' #' + task.hash + ' passed? ' + task.results.passed);

                                                            if (task.results.passed) {
                                                                _context7.next = 5;
                                                                break;
                                                            }

                                                            log.error('A parent task failed: \'' + task.executor + ': ' + task.context + '\', so subtasks were skipped.');
                                                            return _context7.abrupt('return');

                                                        case 5:

                                                            //..otherwise process subtasks
                                                            log.info('Task ' + task.executor + ':' + task.context + ' has Sub-Tasks. Processing..');
                                                            return _context7.abrupt('return', event.handleTasks(event, task).then(function () {
                                                                //..and wait for those too.
                                                                log.info('Sub-Tasks for ' + task.executor + ':' + task.context + ' Completed.');
                                                            }));

                                                        case 7:
                                                        case 'end':
                                                            return _context7.stop();
                                                    }
                                                }
                                            }, _callee7, _this6);
                                        }));

                                        return function (_x10) {
                                            return _ref8.apply(this, arguments);
                                        };
                                    }()));

                                case 1:
                                case 'end':
                                    return _context8.stop();
                            }
                        }
                    }, _callee8, _this6);
                }));

                return function (_x9) {
                    return _ref7.apply(this, arguments);
                };
            }());
            return _promise2.default.all(subtaskPromises);
        }

        /**
         * <details>
         * <summary>TestResult A : PASS</summary>
         * <p>
         * this is a summary of the result with a <a href="https://www.google.com.au">link</a> to more info.
         * </p>
         * </details>
         * @param task
         * @param depth
         * @param commentBody
         * @returns {*}
         */

    }, {
        key: 'addPullRequestComment',
        value: function () {
            var _ref9 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee9(event, commentBody, task) {
                var log, status;
                return _regenerator2.default.wrap(function _callee9$(_context9) {
                    while (1) {
                        switch (_context9.prev = _context9.next) {
                            case 0:
                                log = this.log;
                                // don't add comment to PR if disabled for this event type, or disabled for current task

                                if (!(!event.taskConfig.pull_request.disableComments && (!task || !task.disableComments))) {
                                    _context9.next = 8;
                                    break;
                                }

                                if (commentBody === '') commentBody = 'no comment';
                                log.info('adding PR comment: ' + commentBody);

                                status = _AgentUtils.AgentUtils.createPullRequestStatus(event.eventData, 'N/A', 'COMMENT_ONLY', commentBody);
                                return _context9.abrupt('return', _AgentUtils.AgentUtils.postResultsAndTrigger(status, 'Result for ' + event.eventType + ' => Event ID: ' + event.eventId + '<br/>', log).then(function () {
                                    log.info('PR comment queued.');
                                    log.info('-----------------------------');
                                    return event;
                                }));

                            case 8:
                                log.info('skipping PR comment per .githubTaskManager.json');

                            case 9:
                            case 'end':
                                return _context9.stop();
                        }
                    }
                }, _callee9, this);
            }));

            function addPullRequestComment(_x11, _x12, _x13) {
                return _ref9.apply(this, arguments);
            }

            return addPullRequestComment;
        }()
    }, {
        key: 'addPullRequestSummaryComment',
        value: function () {
            var _ref10 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee10(event) {
                var commentBody, baseUrl;
                return _regenerator2.default.wrap(function _callee10$(_context10) {
                    while (1) {
                        switch (_context10.prev = _context10.next) {
                            case 0:
                                commentBody = '### Results for event id: ' + event.eventId + '\n';

                                event.tasks.forEach(function (task) {
                                    commentBody += '<details>' + EventHandlerPullRequest.buildEventSummary(task, 0, '') + '</details>';
                                });

                                // if elk stack is configured, link to rehydrated logs
                                if (process.env.GTM_ELASTIC_HOST && process.env.GTM_ELASTIC_PORT) {
                                    baseUrl = process.env.GTM_BASE_URL || 'http://localhost:9091';

                                    commentBody += '<a href="' + baseUrl + '/metrics/log/gtm-' + event.eventId + '.txt">View full log</a>';
                                }
                                return _context10.abrupt('return', this.addPullRequestComment(event, commentBody));

                            case 4:
                            case 'end':
                                return _context10.stop();
                        }
                    }
                }, _callee10, this);
            }));

            function addPullRequestSummaryComment(_x14) {
                return _ref10.apply(this, arguments);
            }

            return addPullRequestSummaryComment;
        }()
    }, {
        key: 'handleTaskResult',
        value: function handleTaskResult(event, task, log, startTime) {
            var endTime = new Date().getTime();
            var duration = endTime - startTime;
            if (!task.results.passed) event.failed = true;
            log.info({
                resultType: 'TASK',
                eventType: 'pull_request',
                repo: event.eventData.repository.full_name,
                url: event.eventData.pull_request.html_url,
                executor: task.executor,
                context: task.context,
                duration: duration,
                failed: !task.results.passed
            });
        }
    }], [{
        key: 'buildEventSummary',
        value: function buildEventSummary(task, depth, commentBody) {
            if (!task.disabled && task.results && task.results.message) {
                commentBody += '<summary>' + task.executor + ' : ' + task.context + ' (' + task.hash + ') ' + task.results.message + '</summary>\n';
                commentBody += '<p>' + (task.results.details || '') + '\n' + (task.results.url || '');
                if (task.tasks) {
                    commentBody += '<details>';
                    task.tasks.forEach(function (subtask) {
                        commentBody = EventHandlerPullRequest.buildEventSummary(subtask, depth++, commentBody);
                    });
                    commentBody += '</details>';
                }
                commentBody += '</p>';
            }
            return commentBody;
        }
    }]);
    return EventHandlerPullRequest;
}(_EventHandler2.EventHandler);

_EventHandler2.EventHandler.register('pull_request', EventHandlerPullRequest);