// Path: heroku-deploy/src/main/java/com/heroku/sdk/deploy/lib/OutputAdapter.java
// public interface OutputAdapter {
//     void logInfo(String message);
//     void logDebug(String message);
//     void logWarn(String message);
//     void logError(String message);
//     void logUploadProgress(long uploaded, long contentLength);
// 
//     default void logError(String message, Throwable t) {
//         logError(message);
//         logDebug(Arrays.stream(t.getStackTrace()).map(StackTraceElement::toString).collect(Collectors.joining("\n")));
//     }
// }
// 
// Path: heroku-deploy/src/main/java/com/heroku/sdk/deploy/util/CustomHttpClientBuilder.java
// public class CustomHttpClientBuilder {
// 
//     public static CloseableHttpClient build() {
//         /*
//         Workaround for JDK-8220723 (https://bugs.openjdk.java.net/browse/JDK-8220723)
//         We limit the available protocols to TLS 1.2 to avoid triggering the bug with TLS 1.3.
// 
//         Version 11.0.2 is significant to us as it is the default OpenJDK version on Travis CI for Java 11. Since running
//         on CI/CD is one of the main use-cases for this library, we can justify this workaround for a bug in an older
//         version of the JDK.
// 
//         As soon as 11.0.2 is no longer the default on Travis please consider removing this workaround.
// 
//         Issue: https://github.com/heroku/heroku-maven-plugin/issues/71
//         */
//         if (System.getProperty("java.version").equals("11.0.2")) {
//             final String[] supportedProtocols = new String[] { "TLSv1.2" };
//             final String[] supportedCipherSuites = split(System.getProperty("https.cipherSuites"));
// 
//             LayeredConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
//                     (SSLSocketFactory) SSLSocketFactory.getDefault(),
//                     supportedProtocols, supportedCipherSuites, new DefaultHostnameVerifier(PublicSuffixMatcherLoader.getDefault()));
// 
//             return HttpClientBuilder
//                     .create()
//                     .useSystemProperties()
//                     .setSSLSocketFactory(sslConnectionSocketFactory)
//                     .build();
//         }
// 
//         return HttpClients.createSystem();
//     }
// 
//     private static String[] split(final String s) {
//         if (TextUtils.isBlank(s)) {
//             return null;
//         }
//         return s.split(" *, *");
//     }
// }
// 
// Path: heroku-deploy/src/main/java/com/heroku/sdk/deploy/util/io/UploadProgressHttpEntity.java
// public class UploadProgressHttpEntity implements HttpEntity {
//     private HttpEntity wrappedEntity;
//     private Consumer<Long> progressConsumer;
// 
//     public UploadProgressHttpEntity(HttpEntity wrappedEntity, Consumer<Long> progressConsumer) {
//         this.wrappedEntity = wrappedEntity;
//         this.progressConsumer = progressConsumer;
//     }
// 
//     @Override
//     public boolean isRepeatable() {
//         return wrappedEntity.isRepeatable();
//     }
// 
//     @Override
//     public boolean isChunked() {
//         return wrappedEntity.isChunked();
//     }
// 
//     @Override
//     public long getContentLength() {
//         return wrappedEntity.getContentLength();
//     }
// 
//     @Override
//     public Header getContentType() {
//         return wrappedEntity.getContentType();
//     }
// 
//     @Override
//     public Header getContentEncoding() {
//         return wrappedEntity.getContentEncoding();
//     }
// 
//     @Override
//     public InputStream getContent() throws IOException, UnsupportedOperationException {
//         return wrappedEntity.getContent();
//     }
// 
//     @Override
//     public void writeTo(OutputStream outputStream) throws IOException {
//         CountingOutputStream countingOutputStream = new CountingOutputStream(outputStream, progressConsumer);
//         wrappedEntity.writeTo(countingOutputStream);
//     }
// 
//     @Override
//     public boolean isStreaming() {
//         return wrappedEntity.isStreaming();
//     }
// 
//     @Override
//     @SuppressWarnings("deprecation")
//     public void consumeContent() throws IOException {
//         wrappedEntity.consumeContent();
//     }
// }


import com.heroku.api.HerokuAPI;
import com.heroku.api.Source;
import com.heroku.sdk.deploy.api.*;
import com.heroku.sdk.deploy.lib.OutputAdapter;
import com.heroku.sdk.deploy.util.CustomHttpClientBuilder;
import com.heroku.sdk.deploy.util.io.UploadProgressHttpEntity;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.FileEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import javax.net.ssl.SSLHandshakeException;
import java.io.IOException;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
import java.util.function.BiConsumer;
        if (!buildInfo.status.equals("succeeded")) {
            outputAdapter.logDebug("Failed Build ID: " + buildInfo.id);
            outputAdapter.logDebug("Failed Build Status: " + buildInfo.status);
            outputAdapter.logDebug("Failed Build UpdatedAt: " + buildInfo.updatedAt);
            return false;
        }

        outputAdapter.logInfo("-----> Done");
        return true;
    }

    private static BuildInfo pollForNonPendingBuildInfo(String appName, String buildId, HerokuDeployApi herokuDeployApi) throws IOException, InterruptedException, HerokuDeployApiException {
        for (int i = 0; i < 15; i++) {
            BuildInfo latestBuildInfo = herokuDeployApi.getBuildInfo(appName, buildId);
            if (!latestBuildInfo.status.equals("pending")) {
                return latestBuildInfo;
            }

            Thread.sleep(2000);
        }

        return herokuDeployApi.getBuildInfo(appName, buildId);
    }

    private static void uploadSourceBlob(Path path, URI destination, BiConsumer<Long, Long> progressConsumer) throws IOException {
        long fileSize = Files.size(path);

        CloseableHttpClient client = CustomHttpClientBuilder.build();

        HttpPut request = new HttpPut(destination);
// Path: heroku-deploy/src/main/java/com/heroku/sdk/deploy/lib/OutputAdapter.java
// public interface OutputAdapter {
//     void logInfo(String message);
//     void logDebug(String message);
//     void logWarn(String message);
//     void logError(String message);
//     void logUploadProgress(long uploaded, long contentLength);
// 
//     default void logError(String message, Throwable t) {
//         logError(message);
//         logDebug(Arrays.stream(t.getStackTrace()).map(StackTraceElement::toString).collect(Collectors.joining("\n")));
//     }
// }
// 
// Path: heroku-deploy/src/main/java/com/heroku/sdk/deploy/util/CustomHttpClientBuilder.java
// public class CustomHttpClientBuilder {
// 
//     public static CloseableHttpClient build() {
//         /*
//         Workaround for JDK-8220723 (https://bugs.openjdk.java.net/browse/JDK-8220723)
//         We limit the available protocols to TLS 1.2 to avoid triggering the bug with TLS 1.3.
// 
//         Version 11.0.2 is significant to us as it is the default OpenJDK version on Travis CI for Java 11. Since running
//         on CI/CD is one of the main use-cases for this library, we can justify this workaround for a bug in an older
//         version of the JDK.
// 
//         As soon as 11.0.2 is no longer the default on Travis please consider removing this workaround.
// 
//         Issue: https://github.com/heroku/heroku-maven-plugin/issues/71
//         */
//         if (System.getProperty("java.version").equals("11.0.2")) {
//             final String[] supportedProtocols = new String[] { "TLSv1.2" };
//             final String[] supportedCipherSuites = split(System.getProperty("https.cipherSuites"));
// 
//             LayeredConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
//                     (SSLSocketFactory) SSLSocketFactory.getDefault(),
//                     supportedProtocols, supportedCipherSuites, new DefaultHostnameVerifier(PublicSuffixMatcherLoader.getDefault()));
// 
//             return HttpClientBuilder
//                     .create()
//                     .useSystemProperties()
//                     .setSSLSocketFactory(sslConnectionSocketFactory)
//                     .build();
//         }
// 
//         return HttpClients.createSystem();
//     }
// 
//     private static String[] split(final String s) {
//         if (TextUtils.isBlank(s)) {
//             return null;
//         }
//         return s.split(" *, *");
//     }
// }
// 
// Path: heroku-deploy/src/main/java/com/heroku/sdk/deploy/util/io/UploadProgressHttpEntity.java
// public class UploadProgressHttpEntity implements HttpEntity {
//     private HttpEntity wrappedEntity;
//     private Consumer<Long> progressConsumer;
// 
//     public UploadProgressHttpEntity(HttpEntity wrappedEntity, Consumer<Long> progressConsumer) {
//         this.wrappedEntity = wrappedEntity;
//         this.progressConsumer = progressConsumer;
//     }
// 
//     @Override
//     public boolean isRepeatable() {
//         return wrappedEntity.isRepeatable();
//     }
// 
//     @Override
//     public boolean isChunked() {
//         return wrappedEntity.isChunked();
//     }
// 
//     @Override
//     public long getContentLength() {
//         return wrappedEntity.getContentLength();
//     }
// 
//     @Override
//     public Header getContentType() {
//         return wrappedEntity.getContentType();
//     }
// 
//     @Override
//     public Header getContentEncoding() {
//         return wrappedEntity.getContentEncoding();
//     }
// 
//     @Override
//     public InputStream getContent() throws IOException, UnsupportedOperationException {
//         return wrappedEntity.getContent();
//     }
// 
//     @Override
//     public void writeTo(OutputStream outputStream) throws IOException {
//         CountingOutputStream countingOutputStream = new CountingOutputStream(outputStream, progressConsumer);
//         wrappedEntity.writeTo(countingOutputStream);
//     }
// 
//     @Override
//     public boolean isStreaming() {
//         return wrappedEntity.isStreaming();
//     }
// 
//     @Override
//     @SuppressWarnings("deprecation")
//     public void consumeContent() throws IOException {
//         wrappedEntity.consumeContent();
//     }
// }


// Path: heroku-deploy/src/main/java/com/heroku/sdk/deploy/lib/deploymemt/Deployer.java
import com.heroku.api.HerokuAPI;
import com.heroku.api.Source;
import com.heroku.sdk.deploy.api.*;
import com.heroku.sdk.deploy.lib.OutputAdapter;
import com.heroku.sdk.deploy.util.CustomHttpClientBuilder;
import com.heroku.sdk.deploy.util.io.UploadProgressHttpEntity;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.FileEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import javax.net.ssl.SSLHandshakeException;
import java.io.IOException;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
import java.util.function.BiConsumer;

        if (!buildInfo.status.equals("succeeded")) {
            outputAdapter.logDebug("Failed Build ID: " + buildInfo.id);
            outputAdapter.logDebug("Failed Build Status: " + buildInfo.status);
            outputAdapter.logDebug("Failed Build UpdatedAt: " + buildInfo.updatedAt);
            return false;
        }

        outputAdapter.logInfo("-----> Done");
        return true;
    }

    private static BuildInfo pollForNonPendingBuildInfo(String appName, String buildId, HerokuDeployApi herokuDeployApi) throws IOException, InterruptedException, HerokuDeployApiException {
        for (int i = 0; i < 15; i++) {
            BuildInfo latestBuildInfo = herokuDeployApi.getBuildInfo(appName, buildId);
            if (!latestBuildInfo.status.equals("pending")) {
                return latestBuildInfo;
            }

            Thread.sleep(2000);
        }

        return herokuDeployApi.getBuildInfo(appName, buildId);
    }

    private static void uploadSourceBlob(Path path, URI destination, BiConsumer<Long, Long> progressConsumer) throws IOException {
        long fileSize = Files.size(path);

        CloseableHttpClient client = CustomHttpClientBuilder.build();

        HttpPut request = new HttpPut(destination);
        request.setEntity(new UploadProgressHttpEntity(new FileEntity(path.toFile()), bytes -> progressConsumer.accept(bytes, fileSize)));