package com.rjconsultores.ventaboletos.web.utilerias.api;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

import javax.xml.bind.DatatypeConverter;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.JWSHeader;
import com.nimbusds.jose.JWSObject;
import com.nimbusds.jose.Payload;
import com.nimbusds.jose.crypto.MACSigner;
import com.nimbusds.jwt.JWTClaimsSet;

public class ApiCallRunnable implements Runnable {

	private static Logger log = LogManager.getLogger(ApiCallRunnable.class);
	private static final int minutesExpireToken = 10;
	private String secret = "#KO&Fm4_k.sU9M8`6Mx'F\\\"H:*Qxu]6F4r,)JmZ2Jwafd)I.2[RET'1:)VQ6mG9,";
	
	private final String url;
	private final String tenant;
	private String retorno;
	private String urlBase;
	private String user = "internal";
	private ETipoEnvio tipoEnvio;

	public String getUrl() {
		return url;
	}

	public String getTenant() {
		return tenant;
	}

	public String getRetorno() {
		return retorno;
	}

	public void setRetorno(String retorno) {
		this.retorno = retorno;
	}

	public String getUrlBase() {
		return urlBase;
	}

	public void setUrlBase(String urlBase) {
		this.urlBase = urlBase;
	}

	public ApiCallRunnable(String url, String tenant, String urlOriginal) {
		this.url = url;
		this.tenant = tenant;
		this.urlBase = urlOriginal;
	}	

	public ApiCallRunnable(String url, String tenant, String urlBase, String user, String secret, ETipoEnvio tipoEnvio) {
		super();
		this.secret = secret;
		this.url = url;
		this.tenant = tenant;		
		this.urlBase = urlBase;
		this.user = user;
		this.tipoEnvio = tipoEnvio;
	}

	@SuppressWarnings("deprecation")
	public void run() {
		RequestConfig config = RequestConfig.custom()
	            .setConnectTimeout(5000)
	            .setConnectionRequestTimeout(5000)
	            .setSocketTimeout(5000).build();
		
		HttpUriRequest request;
		
		if(ETipoEnvio.POST.equals(tipoEnvio)) {
			request = new HttpPost(url);	
		} else if(ETipoEnvio.DELETE.equals(tipoEnvio)) {
			request = new HttpDelete(url);	
		} else {
			request = new HttpGet(url);
		}

		UsernamePasswordCredentials creds = null;

		try(CloseableHttpClient client = HttpClients.custom().setDefaultRequestConfig(config).build()) {
			if( user.equals("internal")) {
				secret = getToken();
			}
			creds = new UsernamePasswordCredentials(user, secret);
			request.addHeader(new BasicScheme().authenticate(creds, request));

			if (tenant != null) {
				request.addHeader("x-tenant-id", tenant);
			}

			HttpResponse response = client.execute(request);
			if (response != null && response.getStatusLine() != null) {
				log.info(String.format(":: Response Status Code %d :: Headers = %s", response.getStatusLine().getStatusCode(),Arrays.toString(response.getAllHeaders())));
				HttpEntity responseEntity = response.getEntity();			
				String corpo = EntityUtils.toString(responseEntity);
				log.debug(corpo);
			}

			Integer codigoRetorno = (response != null && response.getStatusLine() != null) ? response.getStatusLine().getStatusCode() : null;

			retorno = montarMensagemRetorno(tenant, urlBase, codigoRetorno, null);

		} catch (Exception e) {
			retorno = montarMensagemRetorno(tenant, urlBase, null, e.getMessage());
			log.error("Ocorreu um erro ao executar a requisição de limpar cache de localidade da API", e);
		}
	}
	private String montarMensagemRetorno(String tenant, String url, Integer codigoRetorno, String mensagemErro) {

		StringBuilder mensagemRetorno = new StringBuilder();
		mensagemRetorno.append("ULR -> ").append(url).append("\n");
		mensagemRetorno.append("tenant -> ").append(tenant).append("\n");
		if (mensagemErro == null) {
			mensagemRetorno.append("Resposta -> ").append((codigoRetorno != null && codigoRetorno.equals(200)) ? "Solicitação de limpeza de cache executada com sucesso, código " + codigoRetorno : "Erro ao enviar solicitação, código " + codigoRetorno);
		} else {
			mensagemRetorno.append("Resposta -> ").append(mensagemErro);
		}

		return mensagemRetorno.toString();
	}
	
	private String getToken() throws JOSEException {
		long ttlMillis = minutesExpireToken * 60000;
		long nowMillis = System.currentTimeMillis();
		long expMillis = nowMillis + ttlMillis;

		JWTClaimsSet claims = new JWTClaimsSet.Builder()
				.claim("sub", new SimpleDateFormat("dd/MM/yyyy HH:mm:ss").format(new Date()))
				.claim("userId", user)
				.claim("role", "ROLE_TOKEN")
				.claim("exp", expMillis)
				.build();

		JWSObject jwsObject = new JWSObject(new JWSHeader(JWSAlgorithm.HS256),
				new Payload(claims.toJSONObject()));

		jwsObject.sign(new MACSigner(DatatypeConverter.parseBase64Binary(secret)));

		return jwsObject.serialize();
	}

	public String getUser() {
		return user;
	}

	public void setUser(String user) {
		this.user = user;
	}
	
	public void setSecret(String secret) {
		this.secret = secret;
	}

	public ETipoEnvio getTipoEnvio() {
		return tipoEnvio;
	}

	public void setTipoEnvio(ETipoEnvio tipoEnvio) {
		this.tipoEnvio = tipoEnvio;
	}

}