package com.github.wmixvideo.correios;

import br.com.correios.webservice.calculador.CResultado;
import br.com.correios.webservice.calculador.CServico;
import br.com.correios.webservice.calculador.CalcPrecoPrazoWS;
import br.com.correios.webservice.calculador.CalcPrecoPrazoWSSoap;

import javax.xml.ws.BindingProvider;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.Optional;

public class WSCorreiosCalculador {

    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("dd/MM/yyyy");
    private final CalcPrecoPrazoWSSoap calculadora;
    private String usuario, senha;

    public WSCorreiosCalculador() {
        this.calculadora = new CalcPrecoPrazoWS().getCalcPrecoPrazoWSSoap();
        this.usuario = null;
        this.senha = null;
    }

    public WSCorreiosCalculador(final String usuario, final String senha) {
        this();
        this.usuario = usuario;
        this.senha = senha;
    }

    public WSCorreiosCalculador setTimeout(final int milliseconds) {
        final Map<String, Object> requestContext = ((BindingProvider) this.calculadora).getRequestContext();
        requestContext.put("com.sun.xml.internal.ws.connect.timeout", milliseconds);
        requestContext.put("com.sun.xml.internal.ws.request.timeout", milliseconds);
        return this;
    }

    /**
     * Calcula o prazo de envio.
     *
     * @param servico   tipo de serviço.
     * @param origem    cep origem.
     * @param destino   cep destino.
     * @param dataEnvio data de envio.
     * @return CServico.
     */
    public final Optional<CServico> calculaPrazoData(final String servico, final String origem, final String destino, final LocalDate dataEnvio) {
        final CResultado retornoCorreios = dataEnvio == null ? this.calculadora.calcPrazo(servico, origem, destino) : this.calculadora.calcPrazoData(servico, origem, destino, dataEnvio.format(DATE_TIME_FORMATTER));
        final List<CServico> servicos = retornoCorreios.getServicos().getCServico();
        return servicos.isEmpty() ? Optional.empty() : Optional.of(servicos.get(0));
    }

    /**
     * Calcula o prazo de envio.
     *
     * @param servico tipo de serviço.
     * @param origem  cep origem.
     * @param destino cep destino.
     * @return CServico.
     */
    public final Optional<CServico> calculaPrazo(final String servico, final String origem, final String destino) {
        return calculaPrazoData(servico, origem, destino, null);
    }

    public final BigDecimal calculaPreco(final String servico, final String origem, final String destino) {
        final CResultado retornoCorreios = calculadora.calcPreco(this.usuario, this.senha, servico, origem, destino, null, 0, null, null, null, null, null, null, null);
        final List<CServico> servicos = retornoCorreios.getServicos().getCServico();
        return servicos.isEmpty() ? null : new BigDecimal(servicos.get(0).getValor());
    }

    public final List<CServico> calculaPrecoPrazo(final List<String> servicos, final String origem, final String destino, final BigDecimal pesoEmKg, final Formato formato, final BigDecimal comprimentoEmCm, final BigDecimal alturaEmCm, final BigDecimal larguraEmCm, final BigDecimal diametroEmCm, final Opcao maoPropria, final BigDecimal valorDeclarado, final Opcao avisoRecebimento) {
        String peso = new DecimalFormat("0.##").format(pesoEmKg);
        String servico = String.join(",", servicos);

        final CResultado retornoCorreios = calculadora.calcPrecoPrazo(this.usuario, this.senha, servico, origem, destino, peso, formato.getCodigo(), comprimentoEmCm, alturaEmCm, larguraEmCm, diametroEmCm, maoPropria.getOpcao(), valorDeclarado, avisoRecebimento.getOpcao());
        return retornoCorreios.getServicos().getCServico();
    }
}

@@ -675,22 +675,16 @@
 private 
-final 
 CalcPrec
@@ -709,16 +709,61 @@
 ladora;%0A
+    private int timeoutMilliseconds = 15000;%0A
     priv
@@ -858,55 +858,11 @@
  = n
-ew CalcPrecoPrazoWS().getCalcPrecoPrazoWSSoap()
+ull
 ;%0A  
@@ -1002,24 +1002,8 @@
 ) %7B%0A
-        this();%0A
     
@@ -1130,24 +1130,394 @@
 iseconds) %7B%0A
+        this.timeoutMilliseconds = milliseconds;%0A        return this;%0A    %7D%0A%0A    private CalcPrecoPrazoWSSoap getCalculadora() %7B%0A        System.setProperty(%22sun.net.client.defaultConnectTimeout%22, String.valueOf(this.timeoutMilliseconds));%0A        if (this.calculadora == null) %7B%0A            this.calculadora = new CalcPrecoPrazoWS().getCalcPrecoPrazoWSSoap();%0A        %7D%0A
         fina
@@ -1675,33 +1675,40 @@
 nnect.timeout%22, 
-m
+timeoutM
 illiseconds);%0A  
@@ -1775,17 +1775,24 @@
 meout%22, 
-m
+timeoutM
 illiseco
@@ -1808,32 +1808,44 @@
      return this
+.calculadora
 ;%0A    %7D%0A%0A    /**
@@ -2282,25 +2282,28 @@
 null ? this.
-c
+getC
 alculadora.c
@@ -2292,32 +2292,34 @@
 s.getCalculadora
+()
 .calcPrazo(servi
@@ -2342,25 +2342,28 @@
 ino) : this.
-c
+getC
 alculadora.c
@@ -2356,24 +2356,26 @@
 tCalculadora
+()
 .calcPrazoDa
@@ -3140,33 +3140,36 @@
 tornoCorreios = 
-c
+getC
 alculadora.calcP
@@ -3154,32 +3154,34 @@
 = getCalculadora
+()
 .calcPreco(this.
@@ -4006,17 +4006,20 @@
 reios = 
-c
+getC
 alculado
@@ -4020,16 +4020,18 @@
 culadora
+()
 .calcPre

Ajuste tratamento timeout construtor webservice