package de.jeyp91.gists;

import com.google.api.client.util.DateTime;
import com.google.common.io.Resources;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPatch;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClientBuilder;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Set;

public class GistProvider {

    private static GistProvider prov = null;
    private JSONArray gistList;
    private String username;
    private String password;

    private GistProvider() {
        readConfig();
        this.gistList = listAllGists();
    }

    private void readConfig() {
        JSONParser jsonParser = new JSONParser();
        URL url = Resources.getResource("Gist_Config.json");
        JSONObject gistConfig = null;

        try {
            String jsonConfig = Resources.toString(url, StandardCharsets.UTF_8);
            //Read JSON file
            gistConfig = (JSONObject) jsonParser.parse(jsonConfig);

        } catch (IOException | ParseException e) {
            e.printStackTrace();
        }
        this.username = gistConfig.get("username").toString();
        this.password = gistConfig.get("password").toString();
    }

    public static GistProvider getInstance() {
        if (prov == null) {
            prov = new GistProvider();
        }
        return prov;
    }

    public JSONArray listAllGists() {
        String gistsRaw = getRawData("https://api.github.com/gists");
        return stringToJSONArray(gistsRaw);
    }

    public DateTime getGistUpdatedTimestamp(String gistDescription) {
        DateTime updated = null;
        for (Object o : this.gistList) {
            JSONObject gist = (JSONObject) o;
            String desc = gist.get("description").toString();
            if (gistDescription.equals(desc)) {
                updated = new DateTime(gist.get("updated_at").toString());
            }
        }
        return updated;
    }

    public String getGistID(String gistDescription) {
        String id = null;
        for (Object o : this.gistList) {
            JSONObject gist = (JSONObject) o;
            String desc = gist.get("description").toString();
            if (gistDescription.equals(desc)) {
                id = gist.get("id").toString();
            }
        }
        return id;
    }

    public String updateGist(String id, String file, String content) throws UnsupportedEncodingException {
        String requestUrl = "https://api.github.com/gists/" + id;
        String auth = this.username + ":" + this.password;
        byte[] encodedAuth = Base64.encodeBase64(
                auth.getBytes(StandardCharsets.ISO_8859_1));
        String authHeader = "Basic " + new String(encodedAuth);

        HttpClient client = HttpClientBuilder
                .create()
                .build();
        HttpPatch request = new HttpPatch(requestUrl);
        request.setHeader(HttpHeaders.AUTHORIZATION, authHeader);
        request.setHeader(HttpHeaders.ACCEPT, "application/vnd.github.v3+json");

        JSONObject contentObject = new JSONObject();
        contentObject.put("content", content);
        JSONObject fileObject = new JSONObject();
        fileObject.put(file, contentObject);
        JSONObject filesObject = new JSONObject();
        filesObject.put("files", fileObject);

        String bodyString = filesObject.toString();

        StringEntity body = new StringEntity(filesObject.toString());
        body.setContentType("application/json");
        body.setContentEncoding("UTF-8");
        request.setEntity(body);

        HttpResponse response = null;
        try {
            response = client.execute(request);
        } catch (IOException e) {
            /* TODO */
            e.printStackTrace();
        }

        BufferedReader rd = null;
        try {
            rd = new BufferedReader(
                    new InputStreamReader(response.getEntity().getContent(), StandardCharsets.UTF_8)
            );
        } catch (IOException e) {
            /* TODO */
            e.printStackTrace();
        }

        StringBuilder result = new StringBuilder();
        String line = "";
        while (true) {
            try {
                line = rd.readLine();
            } catch (IOException e) {
                /* TODO */
                e.printStackTrace();
            }

            // Stop reading if last line was found.
            if (line  == null) break;

            result.append(line);
        }
        return result.toString();
    }

    public JSONArray getTeamIdMatcher() {
        String id = getGistID("Team_ID_Matcher");
        return stringToJSONArray(getFileFromGist(id, "Team_ID_Matcher.json"));
    }

    public String getFileFromGist(String id, String filename) {
        String fileurl = null;
        for (Object o : this.gistList) {
            JSONObject gist = (JSONObject) o;
            JSONObject files = (JSONObject)gist.get("files");
            Set<String> filenames = files.keySet();
            if(filenames.contains(filename)) {
                fileurl = ((JSONObject)files.get(filename)).get("raw_url").toString();
            }
        }

        String content = null;
        if(fileurl != null) {
            content = getRawData(fileurl);
        }
        return content;
    }

    private String getRawData(String requestUrl) {

        String auth = this.username + ":" + this.password;
        byte[] encodedAuth = Base64.encodeBase64(
                auth.getBytes(StandardCharsets.ISO_8859_1));
        String authHeader = "Basic " + new String(encodedAuth);

        HttpClient client = HttpClientBuilder
                .create()
                .build();
        HttpGet request = new HttpGet(requestUrl);
        request.setHeader(HttpHeaders.AUTHORIZATION, authHeader);

        HttpResponse response = null;
        try {
            response = client.execute(request);
        } catch (IOException e) {
            /* TODO */
            e.printStackTrace();
        }

        BufferedReader rd = null;
        try {
            rd = new BufferedReader(
                    new InputStreamReader(response.getEntity().getContent(), "UTF-8")
            );
        } catch (IOException e) {
            /* TODO */
            e.printStackTrace();
        }

        StringBuilder result = new StringBuilder();
        String line = "";
        while (true) {
            try {
                line = rd.readLine();
            } catch (IOException e) {
                /* TODO */
                e.printStackTrace();
            }

            // Stop reading if last line was found.
            if (line  == null) break;

            result.append(line);
        }
        return result.toString();
    }

    private JSONArray stringToJSONArray(String rawData) {

        JSONParser parser = new JSONParser();
        JSONArray data = null;
        try {
            data = (JSONArray) parser.parse(rawData);
        } catch (ParseException e) {
            /* TODO */
            e.printStackTrace();
        }
        return data;
    }

    public String getTippligaConfig(int season, String filename) {
        String id = getGistID("Tippliga_Config_" + season);
        return getFileFromGist(id, filename);
    }

    public String getTippligaBaseConfig(String filename) {
        String id = getGistID("Tippliga_Config_Base");
        return getFileFromGist(id, filename);
    }
}
