#!/usr/bin/env groovy
/*
 * 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.
 */

import static org.hamcrest.Matchers.*

import com.urbancode.release.rest.framework.Clients;
import java.util.Calendar
import com.google.common.base.Function
import com.google.common.collect.Maps
import com.google.common.collect.Ordering
import com.google.common.collect.Sets
import com.ibm.icu.text.DateFormat
import com.urbancode.air.*
import com.urbancode.commons.util.query.QueryFilter.FilterType
import com.urbancode.urelease.endpoint.framework.EmailUtils
import com.urbancode.release.rest.framework.QueryParams.FilterClass
import com.urbancode.release.rest.models.*
import static com.urbancode.release.rest.models.internal.InternalClients.*;
import static com.urbancode.release.rest.framework.Clients.*;
import com.urbancode.release.rest.models.internal.ScheduledDeployment
import com.urbancode.release.rest.models.internal.PluginIntegrationProvider
import com.urbancode.release.rest.models.Event
//----------------------------------------------------------------------------------------------
// Extract parameters
def apTool = new AirPluginTool(this.args[0], this.args[1])
Properties props = apTool.getStepProperties()
File pluginHome = new File(System.getenv('PLUGIN_HOME'))
File templatesDir = new File(pluginHome, 'notification-templates')

def reportName = props['reportName']
def recipients = props['recipients'].tokenize(',')
def frequency = props['frequency']
println "Report name is "+reportName
println "Recipients are "+recipients
println "Frequency is "+frequency

//println System.properties.getProperty("user.dir")
//props.list(System.out)


// Compute relevant dates
DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.SHORT)
DateFormat timeFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT)

def now = Calendar.getInstance()
println "Now: "+timeFormat.format(now.getTimeInMillis())

def startMonth = now.clone()
startMonth.set(Calendar.DAY_OF_MONTH, 1)
midnight(startMonth)
println "Start Month: "+timeFormat.format(startMonth.getTimeInMillis())

def endMonth = startMonth.clone()
endMonth.add(Calendar.MONTH, 1)
println "End Month: "+timeFormat.format(endMonth.getTimeInMillis())

def startWeek = now.clone()
startWeek.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY)
midnight(startWeek)
println "Start Week: "+timeFormat.format(startWeek.getTimeInMillis())

def endWeek = startWeek.clone()
endWeek.add(Calendar.WEEK_OF_YEAR, 1)
println "End Week: "+timeFormat.format(endWeek.getTimeInMillis())

def today = now.clone()
midnight(today)
println "Today: "+timeFormat.format(today.getTimeInMillis())

def thirtyDays = today.clone()
midnight(thirtyDays)
thirtyDays.add(Calendar.DAY_OF_MONTH, 31)
println "Thirty Days: "+timeFormat.format(thirtyDays.getTimeInMillis())



// Get previous last-run date from prop value
Clients.loginWithToken(props['releaseServerUrl'], props['releaseToken']);
PluginIntegrationProvider provider = pluginIntegrationProvider().id(props['releaseIntegrationProvider']).get()
println "Provider props:" + provider.propertyValues.toString()

String lastRunString = provider.getProperty("lastRun-$reportName")
long lastRun = (lastRunString != null)? Long.parseLong(lastRunString): 0L

Calendar lastRunCal = Calendar.getInstance()
lastRunCal.setTimeInMillis(lastRun)
println "Last Run: "+timeFormat.format(lastRun)


// If we are not restricting the frequency of execution
if (frequency.equals("Unrestricted") 
// Or this report has not been run yet
    || (lastRun == 0L)
// Or the frequency is weekly and the last run was before the current week
    || (frequency.equals("Weekly") && lastRunCal.before(startWeek)) 
// Or the frequency is monthly and the last run was before the current month
    || (frequency.equals("Monthly") && lastRunCal.before(startMonth))) {
// Then actually run the report
    
    // Store new last-run date (now) as a prop value
    provider.property("lastRun-$reportName", Long.toString(now.getTimeInMillis())).save()
    
    
    // Load data from REST services
    ScheduledDeployment[] weekProdSDs = getProdSDs(startWeek.getTimeInMillis(), endWeek.getTimeInMillis())
    ScheduledDeployment[] thirtyDaysProdSDs = getProdSDs(today.getTimeInMillis(), thirtyDays.getTimeInMillis())
    Event[] blackoutEvents = event()
        .filter("startDate", FilterClass.LONG, FilterType.GREATER_OR_EQUAL, today.getTimeInMillis())
        .filter("endDate", FilterClass.LONG, FilterType.LESS_THAN, thirtyDays.getTimeInMillis())
        .like("type.name", "Blackout")
        .when().getAll()
    
    
    // Prep template parameters and utilities
    Map<String,Object> context = [
        EmailUtils : EmailUtils.class,
        dateFormat : dateFormat,
        timeFormat : timeFormat,
        startWeekDate : dateFormat.format(startWeek.getTimeInMillis()),
        endWeekDate : dateFormat.format(endWeek.getTimeInMillis()),
        todayDate : dateFormat.format(today.getTimeInMillis()),
        thirtyDaysDate : dateFormat.format(thirtyDays.getTimeInMillis()),
        weeklyDeployments : weekProdSDs,
        thirtyDaysDeployments : thirtyDaysProdSDs,
        blackoutEvents : blackoutEvents,
        tableStyle : "style=\"width:100%; margin-left:auto; margin-right:auto; background-color:#FFFFFF; border-spacing: 0; font-family: helvetica neue, arial, sans-serif; font-weight: 400; font-size: 14px; text-align: left;\"",
        thStyle : "style=\"color: #FFF; background-color: #008ABF; font-weight: 400; padding: 8px 6px;\"",
        tdStyle : "style=\"border-bottom: 1px solid #D0D2D3; padding: 8px 6px; vertical-align: top;\"",
        majorStyle : "style=\"background-color: yellow;\""
    ]
    
    
    // Send the actual email, by applying the selected report template
    EmailUtils.startEmailServices(pluginHome, props)
    EmailUtils.sendEmail(templatesDir, reportName, context, recipients, [])
    EmailUtils.stopEmailServices()
}
else {
    println "NO EMAIL -- Execution suppressed by frequency parameter"
}


//----------------------------------------------------------------------------------------------
// Helper method for setting a calendar's time values to midnight (all zeros)
def Calendar midnight(Calendar cal) {
    cal.with {
        set(Calendar.HOUR_OF_DAY, 0)
        set(Calendar.MINUTE, 0)
        set(Calendar.SECOND, 0)
        set(Calendar.MILLISECOND, 0)
    }
}


//----------------------------------------------------------------------------------------------
// Helper method for loading deployment data
def ScheduledDeployment[] getProdSDs(long startInclusive, long endExclusive) {
    // Helpers for extracting data from and sorting deployments
    def Function<ScheduledDeployment,String> GET_TEAM =
            new Function<ScheduledDeployment,String>() {
        public String apply(ScheduledDeployment sd) {
            return sd.release.team.name
        }
    }

    def Function<ScheduledDeployment,Long> GET_SCHEDULED_START =
            new Function<ScheduledDeployment,Long>() {
        public Long apply(ScheduledDeployment sd) {
            return sd.scheduledDate
        }
    }

    def Ordering<ScheduledDeployment> BY_TEAM_AND_SCHEDULED_DATE =
            Ordering.from(String.CASE_INSENSITIVE_ORDER).nullsLast().onResultOf(GET_TEAM)
            .compound(Ordering.natural().nullsLast().onResultOf(GET_SCHEDULED_START))
            
    // XXX: filters do not appear to be working!
    ScheduledDeployment[] sds = scheduledDeployment()
        .filter("scheduledDate", FilterClass.LONG, FilterType.GREATER_OR_EQUAL, startInclusive)
        .filter("endTimeOverride", FilterClass.LONG, FilterType.LESS_THAN, endExclusive)
        // XXX: switch to equals when this works across joins
        .like("phase.phaseModel.name", "PROD")
        .format("list")
        .when().getAll()

     Collections.sort(Arrays.asList(sds), BY_TEAM_AND_SCHEDULED_DATE)
     return sds
}