package web.multitask.trismegistoservices.config;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.util.*;
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.services.gmail.Gmail;
import com.google.api.services.gmail.GmailScopes;
import org.json.JSONObject;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.services.drive.Drive;
import com.google.api.services.drive.DriveScopes;
import com.google.auth.http.HttpCredentialsAdapter;
import com.google.auth.oauth2.GoogleCredentials;

import javax.annotation.PostConstruct;

@Configuration
public class GoogleConfig {

    private static final JsonFactory JSON_FACTORY = GsonFactory.getDefaultInstance();
    private static final String OAUTH2 = "/oAuth2.json";
    private static final String CREDENTIALS_FOLDER_PATH = "/tokens";
    private final String APPLICATION_NAME = "FullService Application";
    private String refresh_token_gmail = null;
    private String refresh_token_drive = null;
    private String client_id = null;
    private String client_secret = null;

    @PostConstruct
    public void getGoogleCredentials() {
        try {
            InputStream in = GoogleConfig.class.getResourceAsStream(CREDENTIALS_FOLDER_PATH + OAUTH2);
            if (in == null)
                throw new FileNotFoundException("Resource not found: " + CREDENTIALS_FOLDER_PATH + OAUTH2);
            GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));
            client_id = clientSecrets.getDetails().getClientId();
            client_secret = clientSecrets.getDetails().getClientSecret();
            refresh_token_gmail = clientSecrets.getDetails().get("gmail_refresh_token").toString();
            refresh_token_drive = clientSecrets.getDetails().get("drive_refresh_token").toString();
        }catch (IOException e) {
            System.out.println("Error: " + e);
        }
    }

    public Drive getDrive() {
        try {
            NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
            Credential authorize = new GoogleCredential.Builder().setTransport(GoogleNetHttpTransport.newTrustedTransport())
                    .setJsonFactory(JSON_FACTORY)
                    .setClientSecrets(client_id, client_secret)
                    .build()
                    .setAccessToken(getAccessToken(refresh_token_drive))
                    .setRefreshToken(refresh_token_drive);
            return new Drive.Builder(HTTP_TRANSPORT, JSON_FACTORY, authorize)
                    .setApplicationName(APPLICATION_NAME).build();
        } catch (GeneralSecurityException | IOException e) {
            System.out.println("Error: " + e);
            return null;
        }
    }

    public Gmail getGmail() {
        try {
            NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
            Credential authorize = new GoogleCredential.Builder().setTransport(GoogleNetHttpTransport.newTrustedTransport())
                    .setJsonFactory(JSON_FACTORY)
                    .setClientSecrets(client_id, client_secret)
                    .build()
                    .setAccessToken(getAccessToken(refresh_token_gmail))
                    .setRefreshToken(refresh_token_gmail);
            return new Gmail.Builder(HTTP_TRANSPORT, JSON_FACTORY, authorize)
                    .setApplicationName(APPLICATION_NAME).build();
        } catch (GeneralSecurityException | IOException e) {
            System.out.println("Error: " + e);
            return null;
        }
    }

    public String getAccessToken(String refresh_token) {

        try {
            Map<String, Object> params = new LinkedHashMap<>();
            params.put("grant_type", "refresh_token");
            params.put("client_id", client_id);
            params.put("client_secret", client_secret);
            params.put("refresh_token",refresh_token);

            StringBuilder postData = new StringBuilder();
            for (Map.Entry<String, Object> param : params.entrySet()) {
                if (postData.length() != 0) {
                    postData.append('&');
                }
                postData.append(URLEncoder.encode(param.getKey(), "UTF-8"));
                postData.append('=');
                postData.append(URLEncoder.encode(String.valueOf(param.getValue()), "UTF-8"));
            }
            byte[] postDataBytes = postData.toString().getBytes(StandardCharsets.UTF_8);

                URL url = new URL("https://accounts.google.com/o/oauth2/token");
            HttpURLConnection con = (HttpURLConnection) url.openConnection();
            con.setDoOutput(true);
            con.setUseCaches(false);
            con.setRequestMethod("POST");
            con.getOutputStream().write(postDataBytes);

            BufferedReader reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
            StringBuilder buffer = new StringBuilder();
            for (String line = reader.readLine(); line != null; line = reader.readLine()) {
                buffer.append(line);
            }

            JSONObject json = new JSONObject(buffer.toString());
            return json.getString("access_token");
        } catch (Exception ex) {
            System.out.println("Error: " + ex);
        }
        return null;
    }

}