package com.urbancode.air.plugin.reportpublisher;

import org.apache.commons.httpclient.HttpClient
import org.apache.commons.httpclient.UsernamePasswordCredentials
import org.apache.commons.httpclient.auth.AuthScope
import org.apache.commons.httpclient.methods.StringRequestEntity
import org.apache.commons.httpclient.methods.PostMethod
import org.apache.commons.httpclient.methods.multipart.FilePart
import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity
import org.apache.commons.httpclient.methods.multipart.Part
import org.apache.commons.httpclient.methods.multipart.StringPart
import org.apache.commons.httpclient.params.HttpMethodParams
import org.apache.commons.httpclient.protocol.Protocol
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory

import com.urbancode.commons.util.IO
import com.urbancode.commons.util.https.OpenSSLProtocolSocketFactory

import java.io.File

public class UploadHelper {
    
    //**************************************************************************
    // CLASS
    //**************************************************************************
    
    final def boundary = "---------------8jujieu8479wueire584w9en";

    //**************************************************************************
    // INSTANCE
    //**************************************************************************
    public UploadHelper() {
    }
    
    def uploadResult (reportFiles, reportName, jobId) {
        if (!reportFiles) {
            println 'No report was able to be generated'
            return;
        }
        if (reportName == null || reportName.isEmpty()) {
            throw new NullPointerException("Report name must be provided");
        }
        if (jobId == null || jobId.isEmpty()) {
            throw new NullPointerException("A job ID must be provided");
        }

        sendPostRequest(reportName, (File[]) reportFiles.toArray(), jobId)
    }

    private void sendPostRequest(String name, File[] reportFiles, String jobId) {
        def authToken = System.getenv("AUTH_TOKEN")
        String buildLifeId = System.getenv("BUILD_LIFE_ID")
        def reportName = URLEncoder.encode(name)

        // construct the URL with property replacements
        String baseUrl = System.getenv("WEB_URL")

        baseUrl += baseUrl.endsWith("/") ? "" : "/"
        String url = baseUrl + "rest/buildlife/${buildLifeId}/publishedReports"

        println "Sending request to $url"

        ProtocolSocketFactory socketFactory = new OpenSSLProtocolSocketFactory()
        Protocol https = new Protocol("https", socketFactory, 443)
        Protocol.registerProtocol("https", https)

        PostMethod postMethod = new PostMethod(url)
        postMethod.getParams().setParameter(HttpMethodParams.MULTIPART_BOUNDARY, boundary);
        if (authToken) {
            postMethod.setRequestHeader("Authorization-Token", authToken)
            postMethod.setRequestHeader("Content-Type", "multipart/mixed;boundary=${boundary}")
        }

        println "Uploading ${reportFiles.length} files in report \"${name}\" to build life ${buildLifeId}"

        def partsList = new ArrayList<Part>();
        partsList.add(new StringPart("reportName", reportName, "UTF-8"));
        partsList.add(new StringPart("pathSeparator", File.separator, "UTF-8"));
        partsList.add(new StringPart("jobId", jobId, "UTF-8"));

        def i = 0;
        reportFiles.each { reportFile ->
            String uniqueFieldName = "file${i}";
            partsList.add(new FilePart(uniqueFieldName, reportFile.getName(), reportFile));
            i++;
        }

        def multipartEntity = new MultipartRequestEntity(partsList.toArray(new Part[partsList.size()]), postMethod.getParams())
//        multipartEntity.writeRequest(System.out);

        postMethod.setRequestEntity(multipartEntity);

        HttpClient client = new HttpClient()

        def responseCode = client.executeMethod(postMethod)
        InputStream responseStream = postMethod.getResponseBodyAsStream()
        if (isGoodResponseCode(responseCode)) {
            IO.copy(responseStream, System.out)
            println "Successfully uploaded all files"
        }
        else {
            IO.copy(responseStream, System.err)
            throw new RuntimeException("Failed to upload reports. StatusCode: ${responseCode}")
        }
    }

    private boolean isGoodResponseCode(int responseCode) {
        return responseCode >= 200 && responseCode < 300;
    }
}