// (C) Copyright 2020 Hewlett-Packard Enterprise Company, L.P.

define([
    'hp/core/NotificationFormatter',
    'fs/view/settings/backup/BackupTaskIndexNotificationFormatter',
    'hp/core/LinkTargetBuilder',
    'hp/core/StatusState',
    'hp/services/Log'], 
function(notificationFormatter, backupTaskFormatter, linkTargetBuilder, statusState, log) {"use strict";

    var TaskNotificationFormatter = ( function() {
      
        /**
         * @constructor
         * @type {TaskNotificationFormatter}
         */
        function TaskNotificationFormatter() {
          
            function getSubstitutions(context) {
                var result = [];
                var source;
                if (context.data) {
                    if (context.data.substitutions) {
                        source = context.data.substitutions;
                    } else if ('string' === $.type(context.data)){
                        source = context.data;
                    }
                    if (source) {
                        try {
                            var parsed = JSON.parse(source);
                            if ($.isArray(parsed)) {
                                result = parsed;
                            } else {
                                result = [parsed];
                            }
                        } catch (e) {
                            log.warn(e.message);
                        }
                    }
                }
                return result;
            }
          
            function replaceText(context, text) {
                var result = notificationFormatter.replaceInlineLinks(text);
                var substitutions = getSubstitutions(context);
                var length = substitutions.length;
                var substitution;
                for (var i=0; i<length; i++) {
                    substitution = substitutions[i];
                    result = result.replace('\{' + substitution.uri + '\}',
                        '[' + substitution.name + '](#' +
                        linkTargetBuilder.makeLocation(substitution.uri) + ')');
                }
                return result;
            }

            function addDetail(context, text, notification) {
                if (text) {
                    notificationFormatter.addDetail(notification,
                        replaceText(context, text));
                }
            }
            
            function addResolutions(context, resolutions, notification) {
                if (resolutions) {
                    var length = resolutions.length;
                    for (var i=0; i<length; i++) {
                        notificationFormatter.addResolution(notification,
                            replaceText(context, resolutions[i]));
                    }
                }
            }
          
            function formatTask(notification, task) {
                var message, length;
                
                notification.uri = task.uri;
                notification.status = statusState.getHealthStatus(task.taskState);
                notification.state = task.taskState;
                notification.changing =
                    (notification.state.toLowerCase() === 'running');
                notification.summary = task.name;
                notification.timestamp = task.created;
                if ('running' === notification.state.toLowerCase()) {
                    notification.endTimestamp =
                        (new Date(task.__replyTimestamp)).toISOString();
                } else if ('pending' === notification.state.toLowerCase()) {
                    notification.endTimestamp =
                        (new Date(task.__replyTimestamp)).toISOString();
                } else if ('skipped' === notification.state.toLowerCase()) {
                    notification.endTimestamp = null;
                } else {
                    notification.endTimestamp = task.modified;
                }
                notification.owner = task.owner;
                if (task.associatedResource) { // V2
                    notification.sourceUri = task.associatedResource.resourceUri;
                    notification.sourceName = task.associatedResource.resourceName;
                    notification.sourceCategory =
                        task.associatedResource.resourceCategory;
                } else { // V1
                    notification.sourceUri = task.associatedResourceUri;
                }
                notification.progress = task.computedPercentComplete;
                if (task.progressUpdates) {
                    var updates = task.progressUpdates;
                    if (updates && updates.length > 0) {
                        var lastUpdate = updates[updates.length-1];
                        notification.step =
                            replaceText(lastUpdate, lastUpdate.statusUpdate);
                    }
                }
                
                if (task.progressUpdates.length > 0 ||
                    task.taskErrors.length > 0 ||
                    task.taskOutput.length > 0) {

                    notification.details = '';
                    notification.resolution = '';
                    length = task.progressUpdates.length;
                    for (var i=0; i<length; i++) {
                        message = task.progressUpdates[i];
                        addDetail(message, message.statusUpdate, notification);
                    }
                    if (length > 0) {
                        notification.details += '\n';
                    }
                    length = task.taskErrors.length;
                    for (i=0; i<length; i++) {
                        message = task.taskErrors[i];
                        addDetail(message, message.message, notification);
                        addDetail(message, message.details, notification);
                        addResolutions(message, message.recommendedActions, notification);
                    }
                    if (length > 0) {
                        notification.details += '\n';
                    }
                    length = task.taskOutput.length;
                    for (i=0; i<length; i++) {
                        message = task.taskOutput[i];
                        addDetail(message, message.message, notification);
                        addDetail(message, message.details, notification);
                    }
                }

                if (task.actions) {
                    $.each(task.actions, function (index, action) {
                        notificationFormatter.addAction(notification,
                        notificationFormatter.formatLink(action));
                    });
                }
            }
            
            // until everyone publishes a similar status to the index service, convert here
            function workaroundStatus(indexResult) {
                var status = 'unknown';
                if (indexResult.status) {
                    status = statusState.getHealthStatus(indexResult.status);
                } else if (indexResult.state) {
                    status = statusState.getHealthStatus(indexResult.state);
                } else if (indexResult.attributes.state) {
                    status = statusState.getHealthStatus(indexResult.attributes.state);
                }
                return status;
            }
            
            // For tasks coming from index, we do our own computedPercentComplete
            // calculation, since this doesn't get updated in the index service
            function computePecentComplete(indexResource, state) {
                var percent = 0;
                // only running tasks get calculation, all others are forced
                if ('running' === state) {
                    if ((indexResource.attributes.expectedDuration > 0) &&
                        indexResource.created && indexResource.__replyTimestamp) {
                        var createdAt = new Date(indexResource.created);
                        var replyAt = new Date(indexResource.__replyTimestamp);
                        var elapsedSeconds =
                            (replyAt.getTime() - createdAt.getTime()) / 1000.0;
                        percent = Math.ceil((elapsedSeconds /
                            indexResource.attributes.expectedDuration) * 100.0);
                    } else if (indexResource.attributes.percentComplete > 0) {
                        percent = indexResource.attributes.percentComplete;
                    }
                    indexResource.attributes.computedPercentComplete =
                        Math.min(95, percent);
                } else if ('pending' === state || 'new' === state) {
                    indexResource.attributes.computedPercentComplete = 0;
                } else {
                    indexResource.attributes.computedPercentComplete = 100;
                }
            }
            
            function formatIndex(notification, indexResource) {
                notification.uri = indexResource.uri;
                notification.status = workaroundStatus(indexResource);
                notification.state =
                    indexResource.state || indexResource.attributes.state;
                notification.changing = (notification.state &&
                    notification.state.toLowerCase() === 'running');
                notification.summary = indexResource.name;
                notification.timestamp = indexResource.created;
                if ('running' === notification.state.toLowerCase()) {
                    notification.endTimestamp =
                        (new Date(indexResource.__replyTimestamp)).toISOString();
                } else if ('pending' === notification.state.toLowerCase()) {
                    notification.endTimestamp =
                        (new Date(indexResource.__replyTimestamp)).toISOString();
                } else if ('skipped' === notification.state.toLowerCase()) {
                    notification.endTimestamp = null;
                } else {
                    notification.endTimestamp = indexResource.modified;
                }
                notification.owner = indexResource.attributes.owner;
                notification.sourceUri =
                    indexResource.attributes.associatedResourceUri;
                notification.sourceName =
                    indexResource.attributes.associatedResourceName;
                notification.sourceCategory =
                    indexResource.attributes.associatedResourceCategory;
                computePecentComplete(indexResource, notification.state.toLowerCase());
                notification.progress = indexResource.attributes.computedPercentComplete;
                notification.details = indexResource.details;
                if (indexResource.multiAttributes) {
                    var updates = indexResource.multiAttributes.statusUpdate;
                    var timestamps = indexResource.multiAttributes.statusUpdateTimestamp;
                    if (updates && updates.length > 0 && timestamps && timestamps.length > 0) {
                        // figure out which one is the latest
                        var latest = 0;
                        for (var i=0; i<timestamps.length; i++) {
                            if (timestamps[latest] < timestamps[i]) {
                                latest = i;
                            }
                        }
                        var lastUpdate = updates[latest];
                        notification.step = replaceText({}, lastUpdate);
                    }
                }
            }
            
            function format(notification, item) {
                if ('IndexResource' === item.type) {
                    formatIndex(notification, item);
                } else {
                    formatTask(notification, item);
                }
            }
            
            /**
             * @public
             * Register with the NotificationFormatter for any tasks.
             */
            this.register = function () {
                // Need to re-evaluate backup task formatter post Atlas 2.0
                backupTaskFormatter.register(this);
                notificationFormatter.register({
                    category: 'tasks',
                    associatedResourceCategory: 'any',
                    index: true,
                    format: format});
            };
            
            /**
             * @public
             * Populate the notification from the task
             * @param notification Object the notification to populate
             * @param task Object the task to populate from
             */
            this.formatTask = formatTask;
            
            /**
             * @public
             * Populate the notification from the index resource
             * @param notification Object the notification to populate
             * @param index Object the index resource to populate from
             */
            this.formatIndex = formatIndex;
            
            /**
             * @public
             * Populate the notification from the task
             * @param notification Object the notification to populate
             * @param task Object the task to populate from
             */
            this.replaceText = replaceText;
        }

        return new TaskNotificationFormatter();
    }());

    return TaskNotificationFormatter;
});
