/*
 * Licensed Materials - Property of IBM Corp.
 * IBM UrbanCode Release
 * (c) Copyright IBM Corporation 2014. All Rights Reserved.
 *
 * U.S. Government Users Restricted Rights - Use, duplication or disclosure restricted by
 * GSA ADP Schedule Contract with IBM Corp.
 */
package com.urbancode.urelease

import java.io.File;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.text.SimpleDateFormat;

import org.apache.log4j.Logger;

import com.urbancode.release.rest.models.internal.RelatedDeployment;
import com.urbancode.release.rest.models.internal.ScheduledDeployment;
import com.urbancode.release.rest.models.internal.ScheduledDeploymentVersion;
import com.urbancode.release.rest.models.internal.Milestone;
import com.urbancode.release.rest.models.Release;
import com.urbancode.release.rest.models.Application;
import com.urbancode.release.rest.models.Version;
import com.urbancode.release.rest.models.internal.ScheduledDeploymentVersion;
import com.urbancode.release.rest.models.internal.VersionStatus;
import com.urbancode.release.rest.models.internal.Gate;
import com.urbancode.release.rest.models.internal.ApprovalSet;
import com.urbancode.release.rest.models.internal.ApprovalItem;
import com.urbancode.urelease.UrlHelper;
import com.urbancode.commons.util.query.QueryFilter.FilterType;
import com.urbancode.release.rest.framework.QueryParams.FilterClass;
import com.urbancode.release.rest.models.Release.ChangeCount;
/**
 * Utilities to assist with email sending in tests and plugins.
 * @author pcentgraf
 */
public class ReleaseEventContextGenerator {
    protected static Logger log = Logger.getLogger(ReleaseEventContextGenerator.class);

    RelatedDeployment rd;
    String releaseServerUrl;
    def releaseIds;

    public ReleaseEventContextGenerator(RelatedDeployment rd, String releaseServerUrl) {
        this.rd = rd;
        this.releaseServerUrl = releaseServerUrl;

        this.rd.format("details");
        this.rd = this.rd.get();
    }

    public def generateContext() {
        def result = [:]

        result["releaseServerUrl"] = releaseServerUrl

        addGeneralContext(result)

        addMilestoneContext(result)

        addQualityContext(result)

        addWorkItemContext(result)

        addStyleContext(result)

        return result
    }

    private def addGeneralContext(context) {
        def generalContext = [:]

        generalContext["name"] = rd.event.name
        def startDate = rd.event.startDate
        Date date = new Date(startDate)
        def formattedDate = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss").format(date)
        generalContext["formattedDate"] = formattedDate

        addAdvancedGeneralContext(generalContext)

        context["general"] = generalContext;
    }

    private def addAdvancedGeneralContext(context) {
        def generalContext = [:]

        // rd.format("rollup")
        // rd= rd.get()
        def releases = []
        def applicationVersions = []
        def releaseCount = 0
        def sdCount = 0
        def appVersionCount = 0

        ScheduledDeployment query = new ScheduledDeployment();
        query.filter("relatedDeployment.id", FilterClass.UUID, FilterType.EQUALS, this.rd.id);
        query.format("list")
        ScheduledDeployment[] sds = query.getAll();

        releaseIds = []
        def versionIds = []

        for (ScheduledDeployment sd : sds) {
            sdCount++

            if(!releaseIds.contains(sd.release.id)) {
                releaseCount++

                def releaseObj = [:]

                releaseObj["name"] = sd.release.name
                releaseObj["url"] = UrlHelper.concatPaths(releaseServerUrl, "release", sd.release.id)

                releases << releaseObj
                releaseIds << sd.release.id

                sd.format("detail")
                sd = sd.get();

                ScheduledDeploymentVersion[] versions = sd.versions

                for(ScheduledDeploymentVersion version : versions) {
                    if(!versionIds.contains(version.id)) {
                        appVersionCount++
                        def versionObj = [:]

                        versionObj["applicationName"] = version.application.name
                        versionObj["applicationId"] = version.application.id
                        versionObj["versionName"] = version.appVersion.name
                        versionObj["url"] = UrlHelper.concatPaths(releaseServerUrl, "applications", version.application.id)

                        versionIds << version.id

                        applicationVersions << versionObj
                    }
                }
            }
        }

        context["releases"] = releases;
        context["applicationVersions"] = applicationVersions;
        context["releaseCount"] = releaseCount;
        context["sdCount"] = sdCount;
        context["appVersionCount"] = appVersionCount;
    }

    private def addQualityContext(context) {
        def qualityContext = [:]
        def deployments = []

        ScheduledDeployment query = new ScheduledDeployment();
        query.filter("relatedDeployment.id", FilterClass.UUID, FilterType.EQUALS, this.rd.id);
        query.format("list")
        ScheduledDeployment[] sds = query.getAll();

        for (ScheduledDeployment sd : sds) {
            def deploymentObj = [:]

            sd.format("detail")
            sd = sd.get()

            def approvals = []

            if (sd.approval != null) {
                for (ApprovalItem task : sd.approval.tasks) {
                    def approvalObj = [:]
                    approvalObj["name"] = task.name
                    def approvalStatus = "Pending, awaiting approval"
                    def approvalColor = "#000000"
                    if(task.status == "CLOSED") {
                        if (task.result == "SUCCESS") {
                            approvalStatus = "Accepted"
                            approvalColor = "#009933"
                        } else {
                            approvalStatus = "Rejected"
                            approvalColor = "#cc3300"
                        }
                    }
                    approvalObj["status"] = approvalStatus
                    approvalObj["approvalColor"] = approvalColor
                    approvalObj["role"] =  task.executorRole.name

                    approvals << approvalObj
                }
            }

            deploymentObj["approvals"] = approvals


            deploymentObj["name"] = sd.release.name + ", " + sd.environment.name + ", " + new SimpleDateFormat("MM/dd/YYYY HH:MM:SS").format(sd.scheduledDate)
            deploymentObj["url"] = UrlHelper.concatPaths(releaseServerUrl, "scheduledDeployment", sd.id)

            def gateNames = []

            for (Gate gate : sd.phase.phaseModel.gates) {
                gateNames << gate.status.name
            }

            def appIdToVersionMap = [:]
            for (ScheduledDeploymentVersion sdVersion : sd.versions) {
                def versionObj = [:]

                def gateNamesCopy = gateNames.collect()

                versionObj["name"] = sdVersion.appVersion.name
                def statuses = []

                for (VersionStatus vs : sdVersion.appVersion.versionStatuses) {
                    def vsObj = [:]
                    vsObj["name"] = vs.status.name
                    vsObj["dateCreated"] = new SimpleDateFormat("MM/dd/YYYY HH:MM").format(vs.dateCreated)
                    vsObj["user"] = vs.userName
                    vsObj["missing"] = false

                    statuses << vsObj

                    if(gateNamesCopy.contains(vs.status.name)) {
                        def indexToRemove = gateNamesCopy.findIndexOf { it == vs.status.name }
                        gateNamesCopy.remove(indexToRemove)
                    }
                }

                for (String missingGateName : gateNamesCopy) {
                    def missingGateObj = [:]
                    missingGateObj["name"] = missingGateName
                    missingGateObj["missing"] = true
                    statuses << missingGateObj
                }

                versionObj["statuses"] = statuses

                appIdToVersionMap[sdVersion.application.id] = versionObj
            }

            def apps = []
            for (Application app : sd.release.applications) {
                def appObj = [:]

                appObj["name"] = app.name

                if (appIdToVersionMap[app.id] != null) {
                    appObj["version"] = appIdToVersionMap[app.id]
                } else {
                    def noVersionObj = [:]
                    noVersionObj["name"] = "No version selected"
                    appObj["version"] = noVersionObj
                }

                apps << appObj
            }

            deploymentObj["apps"] = apps
            deployments << deploymentObj
        }

        qualityContext["deployments"] = deployments

        context["quality"] = qualityContext
    }

    private def addWorkItemContext(context) {

        def workItemContext = [:]
        def releases = []

        for(def releaseId : releaseIds) {
            def releaseObj = [:]
            Release release = new Release().id(releaseId)
            release.format("detail")
            release = release.get()

            def applications = []

            for (def application : release.applications) {

                def totalAppChangeCount = 0;
                def completeOrAcceptedCount = 0;
                def typeTotalMap = [:]


                /*
                    releases: [
                        name: Release ABC
                        url: impactAnalysisUrl
                        applications: [
                            name: App A
                            total: #
                            new: [
                                count: #
                                percent: %
                                color: #xxxxxx
                            ]
                            inProgress: [
                                count: #
                                percent: %
                                color: #xxxxxx
                            ]
                            complete: [
                                count: #
                                percent: %
                                color: #xxxxxx
                            ]
                            accepted: [
                                count: #
                                percent: %
                                color: #xxxxxx
                            ]
                            other: [
                                count: #
                                percent: %
                                color: #xxxxxx
                            ]
                            types: [
                                [
                                    name: feature
                                    completed: #
                                    total: #
                                ]
                            ]
                        ]
                    ]

                */
                def applicationObj = [:]

                ChangeCount changeCount = application.totalChanges

                def otherKeySet = changeCount.getOther().keySet()

                def otherObj = [:]
                def otherTotal = 0
                for(def key : otherKeySet) {
                    if(key == "total") {
                        otherTotal = changeCount.getOther().get(key).getCount()
                        totalAppChangeCount = totalAppChangeCount + otherTotal
                    } else {
                    }
                }

                def newKeySet = changeCount.getNew().keySet()

                def newObj = [:]
                def newTotal = 0
                for(def key : newKeySet) {
                    if(key == "total") {
                        newTotal = changeCount.getNew().get(key).getCount()
                        totalAppChangeCount = totalAppChangeCount + newTotal
                    } else {

                    }
                }

                def inProgressKeySet = changeCount.getInProgress().keySet()

                def inProgressObj = [:]
                def inProgressTotal = 0
                for(def key : inProgressKeySet) {
                    if(key == "total") {
                        inProgressTotal = changeCount.getInProgress().get(key).getCount()
                        totalAppChangeCount = totalAppChangeCount + inProgressTotal
                    } else {

                    }
                }

                def completedKeySet = changeCount.getCompleted().keySet()

                def completedObj = [:]
                def completedTotal = 0
                for(def key : completedKeySet) {
                    if(key == "total") {
                        completedTotal = changeCount.getCompleted().get(key).getCount()
                        totalAppChangeCount = totalAppChangeCount + completedTotal
                        completeOrAcceptedCount = completeOrAcceptedCount + completedTotal
                    } else {

                    }
                }

                def acceptedKeySet = changeCount.getAccepted().keySet()

                def acceptedObj = [:]
                def acceptedTotal = 0
                for(def key : acceptedKeySet) {
                    if(key == "total") {
                        acceptedTotal = changeCount.getAccepted().get(key).getCount()
                        totalAppChangeCount = totalAppChangeCount + acceptedTotal
                        completeOrAcceptedCount = completeOrAcceptedCount + acceptedTotal
                    } else {

                    }
                }

                applicationObj["name"] = application.name
                applicationObj["total"] = totalAppChangeCount
                applicationObj["completeOrAcceptedCount"] = completeOrAcceptedCount
                if(totalAppChangeCount > 0) {

                    applicationObj["percent"] = Math.round(completeOrAcceptedCount / totalAppChangeCount * 100)
                    def newSerializedObj = [:]
                    newSerializedObj["count"] = newTotal
                    newSerializedObj["percent"] = newTotal / totalAppChangeCount  * 100
                    newSerializedObj["color"] = "#9169bf"
                    applicationObj["new"] = newSerializedObj
                    def otherSerializedObj = [:]
                    otherSerializedObj["count"] = otherTotal
                    otherSerializedObj["percent"] = otherTotal / totalAppChangeCount * 100
                    otherSerializedObj["color"] = "#c767ae"
                    applicationObj["other"] = otherSerializedObj
                    def inProgressSerializedObj = [:]
                    inProgressSerializedObj["count"] = inProgressTotal
                    inProgressSerializedObj["percent"] = inProgressTotal / totalAppChangeCount * 100
                    inProgressSerializedObj["color"] = "#53abcc"
                    applicationObj["inProgress"] = inProgressSerializedObj
                    def completedSerializedObj = [:]
                    completedSerializedObj["count"] = completedTotal
                    completedSerializedObj["percent"] = completedTotal / totalAppChangeCount * 100
                    completedSerializedObj["color"] = "#86b347"
                    applicationObj["completed"] = completedSerializedObj
                    def acceptedSerializedObj = [:]
                    acceptedSerializedObj["count"] = acceptedTotal
                    acceptedSerializedObj["percent"] = acceptedTotal / totalAppChangeCount  * 100
                    acceptedSerializedObj["color"] = "#f0cc00"
                    applicationObj["accepted"] = acceptedSerializedObj
                }

                applications << applicationObj
            }

            releaseObj["applications"] = applications
            releaseObj["name"] = release.name
            releaseObj["url"] = releaseObj["url"] = UrlHelper.concatPaths(releaseServerUrl, "release", release.id) + "#impactAnalysis"
            releases << releaseObj
        }

        workItemContext["releases"] = releases

        context["workItem"] = workItemContext
    }

    private def addMilestoneContext(context) {

        def milestoneContext = [:]
        def releases = []

        for(def releaseId : releaseIds) {
            def releaseObj = [:]
            Release release = new Release().id(releaseId)
            release.format("detail")
            release = release.get()

            releaseObj["name"] = release.name

            def milestonesList = []

            def totalCount = 0
            def completeCount = 0
            def shouldBeDoneCount = 0
            def doneOnTimeCount = 0
            def lateOutstandingCount = 0

            for (def milestone : release.milestones) {
                totalCount++
                def milestoneObj = [:]

                def deadlineDate = milestone.updatedPlanDate != null ? milestone.updatedPlanDate : milestone.originalPlanDate

                def onTime = ""
                def onTimeColor = "#009933"

                def shouldBeDone = (System.currentTimeMillis() > deadlineDate)

                if(shouldBeDone) {
                    shouldBeDoneCount++
                } else if (milestone.status == Milestone.Status.COMPLETED) {
                    shouldBeDoneCount++
                }

                if(milestone.status == Milestone.Status.COMPLETED) {
                    completeCount++
                    if(milestone.actualDate < deadlineDate) {
                        doneOnTimeCount++
                        onTime="Completed On-Time"
                        onTimeColor = "#009933"
                    } else {
                        onTime="Completed Late"
                        onTimeColor = "#000000"
                    }
                } else {
                    if(shouldBeDone) {
                        lateOutstandingCount++
                        onTime="Late Outstanding"
                        onTimeColor = "#cc3300"
                    }
                }

                milestoneObj["name"] = milestone.name
                milestoneObj["status"] = milestone.status
                milestoneObj["plannedDate"] = new SimpleDateFormat("MM/dd/YYYY").format(deadlineDate)

                if(milestone.actualDate != null) {
                    milestoneObj["actualDate"] = new SimpleDateFormat("MM/dd/YYYY").format(milestone.actualDate)
                } else {
                    milestoneObj["actualDate"] = ""
                }

                milestoneObj["onTime"] = onTime
                milestoneObj["onTimeColor"] = onTimeColor

                milestonesList << milestoneObj
            }

            if(totalCount > 0) {
                releaseObj["progressPercent"] = (completeCount / totalCount) * 100
                def onTimeProgress = (doneOnTimeCount / shouldBeDoneCount) * 100
                releaseObj["onTimePercent"] = onTimeProgress

                def onTimeProgressColor = "#ff0000"

                if(onTimeProgress >= 75) {
                    onTimeProgressColor = "#00cc00"
                } else if(onTimeProgress >= 50) {
                    onTimeProgressColor = "#ffcc00"
                }

                releaseObj["onTimeProgressColor"] = onTimeProgressColor
            } else {
                releaseObj["progressPercent"] = 0
            }

            releaseObj["totalCount"] = totalCount
            releaseObj["completeCount"] = completeCount
            releaseObj["shouldBeDoneCount"] = shouldBeDoneCount
            releaseObj["doneOnTimeCount"] = doneOnTimeCount
            releaseObj["lateOutstandingCount"] = lateOutstandingCount
            releaseObj["milestones"] = milestonesList

            releases << releaseObj
        }

        milestoneContext["releases"] = releases

        context["milestone"] = milestoneContext
    }

    private def addStyleContext(context) {
        context["spacerStyle"] = "height: 35px; width: 100%;"
        context["subHeadingStyle"] = "font-weight: bold;font-size: 20px;font-family: sans-serif; margin-top: 10px;"
        context["subSectionStyle"] = "margin-left: 25px; margin-top: 10px;"
        context["indentStyle"] = "margin-left: 15px;"
        context["smallHeadingStyle"] = "font-weight: bolder;font-size: 15px;font-family: sans-serif;"

        context["tableStyle"] = "border-collapse: collapse; text-align: left; width: 100%;"
        context["thStyle"] = "background:-webkit-gradient( linear, left top, left bottom, color-stop(0.05, #006699), color-stop(1, #00557F) );background:-moz-linear-gradient( center top, #006699 5%, #00557F 100% );filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#006699', endColorstr='#00557F');background-color:#006699; color:#FFFFFF; font-size: 15px; font-weight: bold; border-left: 1px solid #0070A8;"
        context["trStyle"] = "padding: 3px 10px;"
        context["tdStyle"] = "padding: 3px 10px; background: #FFFFFF; color: #00496B; border-left: 1px solid #E1EEF4;font-size: 12px;font-weight: normal;"
        context["td-altStyle"] = "padding: 3px 10px; background: #E1EEF4; color: #00496B; border-left: 1px solid #E1EEF4;font-size: 12px;font-weight: normal;"
        context["redTdStyle"] = "padding: 3px 10px; background: #ff8080; color: #00496B; border-left: 1px solid #E1EEF4;font-size: 12px;font-weight: normal;"
        context["lateOutstandingStyle"] = "clear:left; font-weight: bolder; color: #cc3300; margin-top: 5px; margin-bottom: 15px;"
    }
}
