package pro.panopticon.client.awscloudwatch;

import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.services.cloudwatch.AmazonCloudWatch;
import com.amazonaws.services.cloudwatch.AmazonCloudWatchClientBuilder;
import com.amazonaws.services.cloudwatch.model.MetricDatum;
import com.amazonaws.services.cloudwatch.model.PutMetricDataRequest;
import com.amazonaws.services.cloudwatch.model.StandardUnit;
import com.google.common.collect.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Date;
import java.util.List;

import static java.util.stream.Collectors.toList;

public class CloudwatchClient {

    private final Logger LOG = LoggerFactory.getLogger(this.getClass());

    private final AmazonCloudWatch amazonCloudWatch;

    public CloudwatchClient(HasCloudwatchConfig cloudwatchConfig) {
        amazonCloudWatch = AmazonCloudWatchClientBuilder.standard()
                .withCredentials(new AWSStaticCredentialsProvider(cloudwatchConfig))
                .withRegion(cloudwatchConfig.getRegion())
                .build();
    }

    public void sendStatistics(String namespace, List<CloudwatchStatistic> statistics) {
        if (statistics == null || statistics.isEmpty()) {
            return;
        }

        long before = System.currentTimeMillis();

        List<List<CloudwatchStatistic>> partitions = Lists.partition(statistics, 15);

        partitions.parallelStream()
                .forEach(l -> postToCloudwatch(namespace, l));

        long duration = System.currentTimeMillis() - before;

        LOG.info(String.format("Sent %d partitions to CloudWatch for namespace %s in %dms", partitions.size(), namespace, duration));
    }

    private void postToCloudwatch(String namespace, List<CloudwatchStatistic> statistics) {
        List<MetricDatum> metricDatumList = statistics.stream()
                .map(CloudwatchStatistic::toMetricsDatum)
                .collect(toList());

        PutMetricDataRequest request = new PutMetricDataRequest();
        request.setNamespace(namespace);
        request.setMetricData(metricDatumList);

        amazonCloudWatch.putMetricData(request);
    }

    public static class CloudwatchStatistic {
        private String key;
        private Double value;
        private StandardUnit unit;
        private Date date;

        public CloudwatchStatistic(String key, Double value, StandardUnit unit, java.util.Date date) {
            this.key = key;
            this.value = value;
            this.unit = unit;
            this.date = date;
        }

        public CloudwatchStatistic(String key, Double value, StandardUnit unit) {
            this(key, value, unit, new Date());
        }

        public CloudwatchStatistic(String key, Double value) {
            this(key, value, StandardUnit.Count, new Date());
        }

        public MetricDatum toMetricsDatum() {
            MetricDatum metricDatum = new MetricDatum();
            metricDatum.setMetricName(key);
            metricDatum.setTimestamp(date);
            metricDatum.setUnit(unit);
            metricDatum.setValue(value);
            return metricDatum;
        }
    }
}

@@ -91,24 +91,62 @@
 lsProvider;%0A
+import com.amazonaws.regions.Regions;%0A
 import com.a
@@ -192,16 +192,16 @@
 dWatch;%0A
-
 import c
@@ -454,16 +454,55 @@
 rdUnit;%0A
+import com.google.common.base.Strings;%0A
 import c
@@ -918,33 +918,33 @@
 nfig) %7B%0A        
-a
+A
 mazonCloudWatch 
@@ -942,16 +942,43 @@
 oudWatch
+ClientBuilder clientBuilder
  = Amazo
@@ -1012,16 +1012,17 @@
 andard()
+;
 %0A       
@@ -1018,32 +1018,258 @@
 ();%0A        
-        
+if (!Strings.isNullOrEmpty(cloudwatchConfig.getRegion())) %7B%0A            clientBuilder.withRegion(Regions.fromName(cloudwatchConfig.getRegion()));%0A        %7D%0A        if (credentialsProvided(cloudwatchConfig)) %7B%0A            clientBuilder
 .withCredent
@@ -1324,16 +1324,17 @@
 Config))
+;
 %0A       
@@ -1334,24 +1334,27 @@
         
+%7D%0A%0A
         
 .withReg
@@ -1349,74 +1349,569 @@
     
-.withRegion(cloudwatchConfig.getRegion())%0A                .build()
+amazonCloudWatch = clientBuilder.build();%0A    %7D%0A%0A    private boolean credentialsProvided(HasCloudwatchConfig cloudwatchConfig) %7B%0A        boolean hasAccessKey = Strings.isNullOrEmpty(cloudwatchConfig.getAWSAccessKeyId());%0A        if (hasAccessKey != Strings.isNullOrEmpty(cloudwatchConfig.getAWSSecretKey())) %7B%0A            throw new IllegalArgumentException(%22Either Access Key ID or Secret Key is missing. Please provide both, %22 +%0A                    %22or neither if you want to defer to DefaultAWSCredentialsProviderChain%22);%0A        %7D%0A        return hasAccessKey
 ;%0A  

Use DefaultAWSCredentialsProviderChain and/or DefaultAwsRegionProviderChain if configuration is not explicitly provided