package com.heroku;

import com.atlassian.bamboo.build.logger.BuildLogger;
import com.atlassian.bamboo.task.*;
import com.herokuapp.directto.client.DirectToHerokuClient;
import com.herokuapp.directto.client.VerificationException;
import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.util.HashMap;
import java.util.Map;

/**
 * @author Ryan Brainard
 */
public abstract class AbstractDeploymentTask<P extends DeploymentPipeline> implements TaskType {

    /**
     * A sandbox for static methods that don't play well with jMock
     */
    protected static interface StaticSandbox {
        TaskResult success(TaskContext taskContext);
        TaskResult failed(TaskContext taskContext);
    }
    
    private final P pipeline;
    private final StaticSandbox staticSandbox;

    public AbstractDeploymentTask(P pipeline) {
        this(pipeline, new StaticSandbox() {
            @Override
            public TaskResult success(TaskContext taskContext) {
                return TaskResultBuilder.create(taskContext).success().build();
            }

            @Override
            public TaskResult failed(TaskContext taskContext) {
                return TaskResultBuilder.create(taskContext).failed().build();
            }
        });
    }

    public AbstractDeploymentTask(P pipeline, StaticSandbox staticSandbox) {
        this.pipeline = pipeline;
        this.staticSandbox = staticSandbox;
    }

    @NotNull
    @Override
    public TaskResult execute(@NotNull final TaskContext taskContext) throws TaskException {
        final BuildLogger buildLogger = taskContext.getBuildLogger();
        final String apiKey = taskContext.getConfigurationMap().get("apiKey");
        final String appName = taskContext.getConfigurationMap().get("appName");
        final String pipelineName = pipeline.getPipelineName();
        final DirectToHerokuClient client = new DirectToHerokuClient.Builder().setApiKey(apiKey).build();
        // TODO: Add user agent

        buildLogger.addBuildLogEntry("Preparing to deploy to Heroku app [" + appName + "] via [" + pipelineName + "] pipeline");
        
        final Map<String, File> files = new HashMap<String, File>(pipeline.getRequiredFiles().size());
        final String workingDir = taskContext.getWorkingDirectory().getAbsolutePath() + "/";
        for (String file : pipeline.getRequiredFiles()) {
            final String filepath = workingDir + taskContext.getConfigurationMap().get(file);
            buildLogger.addBuildLogEntry("Adding [" + file  + "]: " + filepath);
            files.put(file, new File(filepath));
        }

        try {
            client.verify(pipelineName, appName, files);
        } catch (VerificationException e) {
            for (String msg : e.getMessages()) {
                buildLogger.addErrorLogEntry(msg);
            }
            return staticSandbox.failed(taskContext);
        }

        final Map<String, String> deployResults = client.deploy(pipelineName, appName, files);
        buildLogger.addBuildLogEntry("Deploying...");

        buildLogger.addBuildLogEntry("Deploy results:");
        for (Map.Entry<String, String> result : deployResults.entrySet()) {
            buildLogger.addBuildLogEntry(" - " + result.getKey() + ":" + result.getValue());
        }

        return "success".equals(deployResults.get("status"))
                ? staticSandbox.success(taskContext) 
                : staticSandbox.failed(taskContext);
    }

}

@@ -142,35 +142,143 @@
 client.D
-irectToHerokuClient
+eployRequest;%0Aimport com.herokuapp.directto.client.DirectToHerokuClient;%0Aimport com.herokuapp.directto.client.EventSubscription
 ;%0Aimport
@@ -421,16 +421,16 @@
 ashMap;%0A
-
 import j
@@ -444,16 +444,244 @@
 l.Map;%0A%0A
+import static com.herokuapp.directto.client.EventSubscription.*;%0Aimport static com.herokuapp.directto.client.EventSubscription.Event.POLL_START;%0Aimport static com.herokuapp.directto.client.EventSubscription.Event.UPLOAD_START;%0A%0A
 /**%0A * @
@@ -2955,68 +2955,755 @@
     
-try %7B%0A            client.verify(pipelineName, appName, fil
+final DeployRequest deployRequest = new DeployRequest(pipelineName, appName, files)%0A                .setEventSubscription(new EventSubscription()%0A                        .subscribe(UPLOAD_START, new Subscriber() %7B%0A                            public void handle(Event event) %7B%0A                                buildLogger.addBuildLogEntry(%22Uploading...%22);%0A                            %7D%0A                        %7D)%0A                        .subscribe(POLL_START, new Subscriber() %7B%0A                            public void handle(Event event) %7B%0A                                buildLogger.addBuildLogEntry(%22Deploying...%22);%0A                            %7D%0A                        %7D)%0A                );%0A%0A        try %7B%0A            client.verify(deployRequ
 es
+t
 );%0A 
@@ -3992,90 +3992,21 @@
 loy(
-pipelineName, appName, files);%0A        buildLogger.addBuildLogEntry(%22Deploying...%22
+deployRequest
 );%0A%0A

add deploy request listener for logging upload and deploy separately