package com.prime.sony.ecommerce.config;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;

import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.annotation.SessionScope;

import com.prime.sony.ecommerce.exceptions.ProductServiceException;
import com.prime.sony.ecommerce.model.SalesForceC;
import com.sforce.async.AsyncApiException;
import com.sforce.async.BulkConnection;
import com.sforce.soap.partner.Connector;
import com.sforce.soap.partner.PartnerConnection;
import com.sforce.ws.ConnectorConfig;

//@EnableWebMvc
@Configuration
public class SalesForceConnection {

	private static final Logger log = LoggerFactory.getLogger(SalesForceConnection.class);

	@Autowired
	private SalesForceC salesForceC;

	@Bean
	@Scope(value = WebApplicationContext.SCOPE_APPLICATION)
	public SalesForceClient getSalesForceAccess() throws ProductServiceException {
		log.info("==>SalesForceConnection.getSalesForceAccess()");
		HttpResponse response = null;
		String getResult = null;
		JSONObject jsonObject = null;
		HttpPost httpPost = null;
		HttpClient httpclient = null;
		SalesForceClient salesForceClient = null;

		String loginURL = salesForceC.getLoginUrl() + salesForceC.getGrantService() + "&client_id="
				+ salesForceC.getClientId() + "&client_secret=" + salesForceC.getClientSecret() + "&username="
				+ salesForceC.getUserName() + "&password=" + salesForceC.getPassword();

		try {
			httpPost = new HttpPost(loginURL);
			httpclient = HttpClientBuilder.create().build();
			response = httpclient.execute(httpPost);
			getResult = EntityUtils.toString(response.getEntity());
			jsonObject = (JSONObject) new JSONTokener(getResult).nextValue();
			salesForceClient = new SalesForceClient(jsonObject.getString("access_token"));
		} catch (ClientProtocolException e) {
			log.error("==> Exception at SalesForceConnection.getSalesForceAccess()", e);
			throw new ProductServiceException(e.getMessage(), e.getCause(), null);
		} catch (IOException e) {
			log.error("==> Exception at SalesForceConnection.getSalesForceAccess()", e);
			throw new ProductServiceException(e.getMessage(), e.getCause(), null);
		} catch (JSONException e) {
			log.error("==> Exception at SalesForceConnection.getSalesForceAccess()", e);
			throw new ProductServiceException(e.getMessage(), e.getCause(), null);
		}
		log.info("<==SalesForceConnection.getSalesForceAccess()");
		return salesForceClient;
	}

	@Bean
	public HttpClient getHttpclient() {
		return HttpClientBuilder.create().build();
	}

	@Bean
	@SessionScope
	public PartnerConnection createPartnerConnection() throws ProductServiceException {
		log.info("==>SalesForceConnection.createPartnerConnection()");
		try {
			SalesForceClient salesForceClient = getSalesForceAccess();
			String authEndpoint = getAuthEndpoint(salesForceC.getClientServiceUrl());

			ConnectorConfig config = new ConnectorConfig() {
				{
					setUsername(salesForceC.getUserName());
					setPassword(salesForceC.getPassword());
					setSessionId(salesForceClient.getAccessToken());
					setAuthEndpoint(authEndpoint);
					setServiceEndpoint(authEndpoint);
				}
			};
			log.info("==>SalesForceConnection.createPartnerConnection()");
			return Connector.newConnection(config);
		} catch (Exception e) {
			log.error("==> Exception at SalesForceConnection.createPartnerConnection()", e);
			throw new ProductServiceException(e.getMessage(), e.getCause(), null);
		}
	}

	@Bean
	@Scope(value = WebApplicationContext.SCOPE_APPLICATION)
	public BulkConnection createBulkConnection() throws AsyncApiException, ProductServiceException {
		log.info("==>SalesForceConnection.createBulkConnection()");
		BulkConnection connection = null;
		try {
			ConnectorConfig partnerConfig = new ConnectorConfig();
			SalesForceClient salesForceClient = getSalesForceAccess();
			partnerConfig.setUsername(salesForceC.getUserName());
			partnerConfig.setPassword(salesForceC.getPassword());
			partnerConfig.setSessionId(salesForceClient.getAccessToken());
			String authEndpoint = getAuthEndpoint(salesForceC.getClientServiceUrl());
			partnerConfig.setAuthEndpoint(authEndpoint);
			partnerConfig.setServiceEndpoint(authEndpoint);
			// new PartnerConnection(partnerConfig);

			ConnectorConfig config = new ConnectorConfig();
			config.setSessionId(partnerConfig.getSessionId());
			// The endpoint for the Bulk API service is the same as for the
			// normal
			// SOAP uri until the /Soap/ part. From here it's
			// '/async/versionNumber'
			String soapEndpoint = partnerConfig.getServiceEndpoint();
			String apiVersion = "47.0";
			String restEndpoint = soapEndpoint.substring(0, soapEndpoint.indexOf("Soap/")) + "async/" + apiVersion;
			config.setRestEndpoint(restEndpoint);
			// This should only be false when doing debugging.
			config.setCompression(true);
			// Set this to true to see HTTP requests and responses on stdout
			config.setTraceMessage(false);
			connection = new BulkConnection(config);
		} catch (Exception ce) {
			log.error("==> Exception at SalesForceConnection.createBulkConnection() ", ce);
			throw new ProductServiceException(ce.getMessage(), ce.getCause(), null);
		}
		log.info("<==SalesForceConnection.createBulkConnection()");
		return connection;
	}

	private String getAuthEndpoint(String loginURL) {
		log.info("==> SalesForceConnection.getAuthEndpoint()");
		try {
			URI loginURI = new URI(loginURL);
			return new URI(loginURI.getScheme(), loginURI.getUserInfo(), loginURI.getHost(), loginURI.getPort(),
					"/services/Soap/u/47.0", null, null).toString();
		} catch (URISyntaxException e) {
			System.out.println(e.getMessage());
			log.error("==> Exception at SalesForceConnection.getAuthEndpoint() ", e);

		}
		log.info("<== SalesForceConnection.getAuthEndpoint()");
		return loginURL;
	}

}
