package com.airbnb.chancery;

import com.airbnb.chancery.model.RateLimitStats;
import com.airbnb.chancery.model.ReferenceCreationRequest;
import com.sun.jersey.api.client.*;
import com.sun.jersey.api.client.filter.ClientFilter;
import lombok.extern.slf4j.Slf4j;

import javax.annotation.Nullable;
import javax.validation.constraints.NotNull;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;

@Slf4j
public class GithubClient {
    private final WebResource resource;

    GithubClient(final @NotNull Client client, final @Nullable String oAuth2Token) {
        client.setFollowRedirects(true);

        resource = client.resource("https://api.github.com/");

        resource.addFilter(new ClientFilter() {
            @Override
            public ClientResponse handle(ClientRequest cr) throws ClientHandlerException {
                /* Github API *requires* this */
                cr.getHeaders().putSingle("User-Agent", "chancery by pierre@gcarrier.fr");
                return getNext().handle(cr);
            }
        });

        if (oAuth2Token != null && !oAuth2Token.isEmpty()) {
            final String authValue = "token " + oAuth2Token;
            resource.addFilter(new ClientFilter() {
                @Override
                public ClientResponse handle(ClientRequest cr) throws ClientHandlerException {
                    cr.getHeaders().putSingle("Authorization", authValue);
                    return getNext().handle(cr);
                }
            });
        } else {
            GithubClient.log.warn("No Github oAuth2 token provided");
        }
    }

    public RateLimitStats getRateLimitData()
            throws GithubFailure.forRateLimit {
        try {
            return resource.uri(new URI("/rate_limit")).
                    accept(MediaType.APPLICATION_JSON_TYPE).
                    get(RateLimitStats.Container.class).getRate();
        } catch (URISyntaxException e) {
            return null; /* mkay? */
        } catch (UniformInterfaceException e) {
            throw new GithubFailure.forRateLimit(e);
        }
    }

    public void createReference(String owner, String repository, String ref, String id)
            throws GithubFailure.forRateLimit {
        final URI uri = UriBuilder.
                fromPath("/repos/{a}/{b}/git/{c}").
                build(owner, repository, ref);

        final ReferenceCreationRequest req = new ReferenceCreationRequest(ref, id);

        try {
            resource.uri(uri).
                    accept(MediaType.APPLICATION_JSON_TYPE).
                    entity(req, MediaType.APPLICATION_JSON_TYPE).
                    post(ReferenceCreationRequest.class);
        } catch (UniformInterfaceException e) {
            throw new GithubFailure.forRateLimit(e);
        }
    }

    public Path download(String owner, String repository, String id)
            throws IOException, GithubFailure.forDownload {
        final Path tempPath = Files.createTempFile("com.airbnb.chancery", null);
        tempPath.toFile().deleteOnExit();

        final URI uri = UriBuilder.
                fromPath("/repos/{a}/{b}/tarball/{c}").
                build(owner, repository, id);

        log.info("Downloading {}", uri);

        try {
            final InputStream inputStream = resource.uri(uri).
                    accept(MediaType.WILDCARD_TYPE).
                    get(InputStream.class);

            Files.copy(inputStream, tempPath, StandardCopyOption.REPLACE_EXISTING);
            log.info("Downloaded {}", uri);
            return tempPath;
        } catch (UniformInterfaceException e) {
            throw new GithubFailure.forDownload(e);
        }
    }
}

@@ -131,16 +131,127 @@
 equest;%0A
+import com.fasterxml.jackson.core.JsonProcessingException;%0Aimport com.fasterxml.jackson.databind.ObjectMapper;%0A
 import c
@@ -801,16 +801,76 @@
 esource;
+%0A    private final ObjectMapper mapper = new ObjectMapper();
 %0A%0A    Gi
@@ -2115,24 +2115,45 @@
 rn resource.
+%0A                    
 uri(new URI(
@@ -2614,32 +2614,40 @@
 Failure.forR
-ateLimit
+eferenceCreation
  %7B%0A        f
@@ -2718,19 +2718,20 @@
 %7Bb%7D/git/
-%7Bc%7D
+refs
 %22).%0A    
@@ -2769,13 +2769,8 @@
 tory
-, ref
 );%0A%0A
@@ -2884,85 +2884,176 @@
     
-resource.uri(uri).%0A                    accept(MediaType.APPLICATION_JSON_TYPE
+/* Github wants a Content-Length, and Jersey doesn't fancy doing that */%0A            final byte%5B%5D payload = mapper.writeValueAsBytes(req);%0A%0A            resource.uri(uri
 ).%0A 
@@ -3075,20 +3075,13 @@
     
-entity(req, 
+type(
 Medi
@@ -3139,58 +3139,61 @@
 ost(
-ReferenceCreationRequest.class);%0A        %7D catch (
+payload);%0A        %7D catch (JsonProcessingException %7C 
 Unif
@@ -3255,32 +3255,40 @@
 Failure.forR
-ateLimit
+eferenceCreation
 (e);%0A       

fix ref creation (that one was horrible)