package factura40;

/*import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.S3Object;
import com.amazonaws.services.s3.model.S3ObjectInputStream;*/
//import com.arrebol.taxiservicios.controller.admin.CustomerController;
//import com.arrebol.taxiservicios.controller.catalog.ProductController;
import com.arrebol.taxiservicios.model.admin.Expense;
import com.arrebol.taxiservicios.model.admin.Service;
import com.arrebol.taxiservicios.model.catalog.Location;
import com.arrebol.taxiservicios.model.core.Person;
import com.arrebol.taxiservicios.model.core.PersonCommercialInvoice;
import com.arrebol.taxiservicios.model.stocktaking.view.KardexInStocktakingView;
import com.arrebol.taxiservicios.model.stocktaking.view.KardexOutStocktakingView;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.faces.context.FacesContext;
import javax.imageio.ImageIO;
import javax.mail.MessagingException;
import javax.swing.JOptionPane;
import javax.swing.WindowConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import net.sf.jasperreports.engine.JRException;
import org.apache.commons.ssl.Base64;
import org.apache.commons.ssl.PKCS8Key;

public class GenerarXML {

    private DataFile blobXml;
    String sellocfdi = null;
    Double subTotalFinalTraslados = 0d;
    ArrayList<String> sumaTrasladosExentos = new ArrayList<>();

    public int generadorXML(Person dataCliente, Double dataTotal, String dataMetodoPago,
            Location dataLocation, PersonCommercialInvoice dataCommercialInvoice, String usoCFDI,
            List<Service> dataServicios, List<KardexOutStocktakingView>dataOrdenesDeServicio, List <KardexInStocktakingView> dataCompras,
    List<Expense> dataGastos) throws FileNotFoundException, TransformerException, TransformerConfigurationException, GeneralSecurityException, IOException  {
        //Inicio de las variables para pruebas

        PersonCommercialInvoice dataClienteDatosFactura = dataCommercialInvoice;
        /*CustomerController controCliente = new CustomerController();
        ArrayList<KardexInStocktakingView> selectedDetailCompras = (ArrayList<KardexInStocktakingView>) dataCompras;
        ArrayList<KardexOutStocktakingView> selectedDetailOrdenesDeServicio = (ArrayList<KardexOutStocktakingView>) dataOrdenesDeServicio;
        ArrayList<Expense> selectedGastos = (ArrayList<Expense>) dataGastos;
        ArrayList<Service> selectedServicesToPay = (ArrayList<Service>) dataServicios;
        Location datosEmisor = dataLocation;
        Person datosReceptor = dataCliente;*/
        /*
        Factura factura = new Factura();
        CFactura controladorFactura = new CFactura();
        CDetalleVenta controladorDetalleVenta = new CDetalleVenta();
        ArrayList<DetalleVenta> detalleVenta = new ArrayList<>();
         */
        //Estos valores se llenan de manera automatica.
        ArrayList<String> respuesta = new ArrayList<>();
        Comprobante40 nuevoComprobante = new Comprobante40();
        nuevoComprobante.setXmlnsCfdi("http://www.sat.gob.mx/cfd/4");
        nuevoComprobante.setXmlnsXsi("http://www.w3.org/2001/XMLSchema-instance");
        nuevoComprobante.setXsiSchemaLocation("http://www.sat.gob.mx/cfd/4 http://www.sat.gob.mx/sitio_internet/cfd/4/cfdv40.xsd");
        nuevoComprobante.setVersion("4.0");
        //Comentarlo despues con Oscar
        nuevoComprobante.setSerie("CAR-1");
        nuevoComprobante.setFolio("1");
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
        Timestamp ts = new Timestamp(System.currentTimeMillis());
        String timestamp = sdf.format(ts);
        //Metodo de punto de venta
        SimpleDateFormat formatoFecha = null; 
            formatoFecha = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
        formatoFecha.setTimeZone(TimeZone.getTimeZone("GMT-06:00"));
        
        
        
        nuevoComprobante.setFecha(formatoFecha.format(new Date()));

        //Cambio pendiente: Forma de pago
        nuevoComprobante.setFormaPago("G01");
        ArrayList<String> tiposTasaOCuota = new ArrayList<>();
        //Cambio pendiente: numeroCertificado desde BD
        nuevoComprobante.setNoCertificado("00001000000517341701");
        //Cambio pendiente: certificado desde BD
        nuevoComprobante.setCertificado("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");
        //Cambio pendiente: obtener el valor de formulario, son efectivo, trasnferencia, etc
        nuevoComprobante.setCondicionesDePago("EFECTIVO");
        //Queda iguanas
        nuevoComprobante.setMonedaComprobante(CMoneda.MXN);
        nuevoComprobante.setTipoCambio(1);
        nuevoComprobante.setTotal(Double.valueOf(formatearDecimales(dataTotal)));
        nuevoComprobante.setTipoDeComprobante(CTipoDeComprobante.I);
        nuevoComprobante.setExportacion("01");
        nuevoComprobante.setMetodoPago(CMetodoPago.fromValue(dataMetodoPago));
        nuevoComprobante.setLugarExpedicion(dataLocation.getPostalCode());
        Comprobante40.Emisor emisor = new Comprobante40.Emisor();
        /*emisor.setNombre(datosEmisor.getBusinessName().toUpperCase());
        emisor.setRegimenFiscal(datosEmisor.getTaxRegime().getRegimenFiscal());
        emisor.setRfc(datosEmisor.getRfc().toUpperCase());*/
        nuevoComprobante.setEmisor(emisor);
        Comprobante40.Receptor receptor = new Comprobante40.Receptor();
        receptor.setNombre(dataClienteDatosFactura.getBusinessName().toUpperCase());
        receptor.setDomicilioFiscalReceptor(dataClienteDatosFactura.getPostalCode());
        receptor.setRfc(dataClienteDatosFactura.getRfc());
        //De momento se tomara el de la empresa, pero se tiene que tomar el de la persona
        //receptor.setRegimenFiscalReceptor(datosReceptor.getRegimenFiscal().getRegimenFiscal());
        //Se debe tomar del cliente
        receptor.setUsoCFDI(CUsoCFDI.fromValue(usoCFDI));
        nuevoComprobante.setReceptor(receptor);
        //Se llena el nodo de concepto con servicios..................................................

        Conceptos listasConcepto = new Conceptos();
        Conceptos.Concepto.Impuestos.Traslados listaTrasladosImportesFinales = new Conceptos.Concepto.Impuestos.Traslados();
        /*for (int i = 0; i <= selectedServicesToPay.size() - 1; i++) {
            Conceptos.Concepto.Impuestos.Traslados listaTraslados = new Conceptos.Concepto.Impuestos.Traslados();
            String valorUnitarioRedondeado;
            Conceptos.Concepto nuevoConcepto = new Conceptos.Concepto();
            Conceptos.Concepto.Impuestos impuestos = new Conceptos.Concepto.Impuestos();
            Conceptos.Concepto.Impuestos.Traslados.Traslado trasnlado = new Conceptos.Concepto.Impuestos.Traslados.Traslado();
            nuevoConcepto.setClaveProdServ(selectedServicesToPay.get(i).getClaveProductoServicio().getCodigo());
            nuevoConcepto.setClaveUnidad(selectedServicesToPay.get(i).getClaveUnidad().getClaveUnidad());
            //Al ser un servicio, la cantidad siempre es 1
            nuevoConcepto.setCantidad(1d);
            nuevoConcepto.setDescripcion(selectedServicesToPay.get(i).getName());
            if (nuevoComprobante.getTipoDeComprobante().equals(CTipoDeComprobante.P)) {
                nuevoConcepto.setValorUnitario("0.00");
            } else {
                //Calculos individuales si un producto maneja iva o no
                //Se obtiene el iva del producto, al parecer al menos de momento, siempre es 16
                String ivaProducto = "16";
                Double impuestoMultiplicar = 0d;
                if (ivaProducto.equals("16")) {
                    impuestoMultiplicar = 1.16;
                } else if (ivaProducto.equals("11")) {
                    impuestoMultiplicar = 1.11;
                } else if (ivaProducto.equals("8")) {
                    impuestoMultiplicar = 1.08;
                } else if (ivaProducto.equals("0")) {
                    impuestoMultiplicar = 1d;
                } else if (ivaProducto.equals("EXENTA")) {
                    impuestoMultiplicar = 1d;
                }
                Double valorUnitario = (selectedServicesToPay.get(i).getCharge() / impuestoMultiplicar);
                //Al ser servicio, siempre es 1
                valorUnitario = valorUnitario / (1);
                valorUnitarioRedondeado = formatearDecimales6(valorUnitario);
                nuevoConcepto.setValorUnitario(valorUnitarioRedondeado);
                //Al ser servicio, siempre es 1
                trasnlado.setBase(formatearDecimales6((Double.parseDouble(valorUnitarioRedondeado) * 1)));
                subTotalFinalTraslados += Double.valueOf(trasnlado.getBase());
                if (ivaProducto.equals("EXENTA")) {
                    trasnlado.setTipoFactor(CTipoFactor.EXENTO);
                } else {
                    trasnlado.setTipoFactor(CTipoFactor.TASA);
                }
                trasnlado.setImpuesto("002");
                if (ivaProducto.equals("EXENTA")) {
                    listaTraslados.setTranslado(trasnlado);
                    impuestos.setTraslados(listaTraslados);
                    tiposTasaOCuota.add("Exento");
                    nuevoConcepto.setObjetoImp("02");
                    listaTrasladosImportesFinales.setTranslado(trasnlado);
                    sumaTrasladosExentos.add(trasnlado.getBase());

                } else {
                    nuevoConcepto.setObjetoImp("02");
                    trasnlado.setTasaOCuota(formatearDecimalesIVA(Double.valueOf(ivaProducto) / 100.00));
                    tiposTasaOCuota.add(String.valueOf(trasnlado.getTasaOCuota()));
                    trasnlado.setImporte(formatearDecimales6(Double.valueOf(trasnlado.getBase()) * (Double.valueOf(trasnlado.getTasaOCuota()))));
                    listaTraslados.setTranslado(trasnlado);
                    impuestos.setTraslados(listaTraslados);
                    listaTrasladosImportesFinales.setTranslado(trasnlado);
                    sumaTrasladosExentos.add("");
                }
            }
            nuevoConcepto.setImporte(Double.valueOf(trasnlado.getBase()));
            nuevoConcepto.setImpuestos(impuestos);
            listasConcepto.setConcepto(nuevoConcepto);
        }*/
        //Se llena el nodo CONCEPTO con ordenes y servicios
        /*for (int i = 0; i <= selectedDetailOrdenesDeServicio.size() - 1; i++) {
            Conceptos.Concepto.Impuestos.Traslados listaTraslados = new Conceptos.Concepto.Impuestos.Traslados();
            String valorUnitarioRedondeado;
            Conceptos.Concepto nuevoConcepto = new Conceptos.Concepto();
            Conceptos.Concepto.Impuestos impuestos = new Conceptos.Concepto.Impuestos();
            Conceptos.Concepto.Impuestos.Traslados.Traslado trasnlado = new Conceptos.Concepto.Impuestos.Traslados.Traslado();
            ProductController productController = new ProductController();
            nuevoConcepto.setClaveProdServ(productController.findProductById(selectedDetailOrdenesDeServicio.get(i).getProductId()).getClaveProductoServicio().getCodigo());
            nuevoConcepto.setClaveUnidad(productController.findProductById(selectedDetailOrdenesDeServicio.get(i).getProductId()).getClaveUnidad().getClaveUnidad());
            //Al ser un servicio, la cantidad siempre es 1
            nuevoConcepto.setCantidad(Double.valueOf(selectedDetailOrdenesDeServicio.get(i).getCantidad()));
            nuevoConcepto.setDescripcion(selectedDetailOrdenesDeServicio.get(i).getProducto());
            if (nuevoComprobante.getTipoDeComprobante().equals(CTipoDeComprobante.P)) {
                nuevoConcepto.setValorUnitario("0.00");
            } else {
                //Calculos individuales si un producto maneja iva o no
                //Se obtiene el iva del producto, al parecer al menos de momento, siempre es 16
                String ivaProducto = "16";
                Double impuestoMultiplicar = 0d;
                if (ivaProducto.equals("16")) {
                    impuestoMultiplicar = 1.16;
                } else if (ivaProducto.equals("11")) {
                    impuestoMultiplicar = 1.11;
                } else if (ivaProducto.equals("8")) {
                    impuestoMultiplicar = 1.08;
                } else if (ivaProducto.equals("0")) {
                    impuestoMultiplicar = 1d;
                } else if (ivaProducto.equals("EXENTA")) {
                    impuestoMultiplicar = 1d;
                }
                Double valorUnitario = (selectedDetailOrdenesDeServicio.get(i).getTotal() / impuestoMultiplicar);
                //Al ser servicio, siempre es 1
                valorUnitario = valorUnitario / selectedDetailOrdenesDeServicio.get(i).getCantidad();
                valorUnitarioRedondeado = formatearDecimales6(valorUnitario);
                nuevoConcepto.setValorUnitario(valorUnitarioRedondeado);
                //Al ser servicio, siempre es 1
                trasnlado.setBase(formatearDecimales6((Double.parseDouble(valorUnitarioRedondeado) * 1)));
                subTotalFinalTraslados += Double.valueOf(trasnlado.getBase());
                if (ivaProducto.equals("EXENTA")) {
                    trasnlado.setTipoFactor(CTipoFactor.EXENTO);
                } else {
                    trasnlado.setTipoFactor(CTipoFactor.TASA);
                }
                trasnlado.setImpuesto("002");
                if (ivaProducto.equals("EXENTA")) {
                    listaTraslados.setTranslado(trasnlado);
                    impuestos.setTraslados(listaTraslados);
                    tiposTasaOCuota.add("Exento");
                    nuevoConcepto.setObjetoImp("02");
                    listaTrasladosImportesFinales.setTranslado(trasnlado);
                    sumaTrasladosExentos.add(trasnlado.getBase());

                } else {
                    nuevoConcepto.setObjetoImp("02");
                    trasnlado.setTasaOCuota(formatearDecimalesIVA(Double.valueOf(ivaProducto) / 100.00));
                    tiposTasaOCuota.add(String.valueOf(trasnlado.getTasaOCuota()));
                    trasnlado.setImporte(formatearDecimales6(Double.valueOf(trasnlado.getBase()) * (Double.valueOf(trasnlado.getTasaOCuota()))));
                    listaTraslados.setTranslado(trasnlado);
                    impuestos.setTraslados(listaTraslados);
                    listaTrasladosImportesFinales.setTranslado(trasnlado);
                    sumaTrasladosExentos.add("");
                }
            }
            nuevoConcepto.setImporte(Double.valueOf(trasnlado.getBase()));
            nuevoConcepto.setImpuestos(impuestos);
            listasConcepto.setConcepto(nuevoConcepto);
        }*/
        
        //Se llena el nodo CONCEPTO con compras
        /*for (int i = 0; i <= selectedGastos.size() - 1; i++) {
            Conceptos.Concepto.Impuestos.Traslados listaTraslados = new Conceptos.Concepto.Impuestos.Traslados();
            String valorUnitarioRedondeado;
            Conceptos.Concepto nuevoConcepto = new Conceptos.Concepto();
            Conceptos.Concepto.Impuestos impuestos = new Conceptos.Concepto.Impuestos();
            Conceptos.Concepto.Impuestos.Traslados.Traslado trasnlado = new Conceptos.Concepto.Impuestos.Traslados.Traslado();
            //Pendiente: Tomar el valor real, se sigue desarrollando
            nuevoConcepto.setClaveProdServ("01010101");
            //Pendiente: Tomar el valor real, se sigue desarrollando
            nuevoConcepto.setClaveUnidad("H87");
            nuevoConcepto.setCantidad(Double.valueOf(selectedDetailCompras.get(i).getCantidad()));
            nuevoConcepto.setDescripcion(selectedDetailCompras.get(i).getProducto());
            if (nuevoComprobante.getTipoDeComprobante().equals(CTipoDeComprobante.P)) {
                nuevoConcepto.setValorUnitario("0.00");
            } else {
                //Calculos individuales si un producto maneja iva o no
                //Se obtiene el iva del producto, al parecer al menos de momento, siempre es 16
                String ivaProducto = "16";
                Double impuestoMultiplicar = 0d;
                if (ivaProducto.equals("16")) {
                    impuestoMultiplicar = 1.16;
                } else if (ivaProducto.equals("11")) {
                    impuestoMultiplicar = 1.11;
                } else if (ivaProducto.equals("8")) {
                    impuestoMultiplicar = 1.08;
                } else if (ivaProducto.equals("0")) {
                    impuestoMultiplicar = 1d;
                } else if (ivaProducto.equals("EXENTA")) {
                    impuestoMultiplicar = 1d;
                }
                Double valorUnitario = (selectedDetailCompras.get(i).getTotal() / impuestoMultiplicar);
                //Al ser servicio, siempre es 1
                valorUnitario = valorUnitario / selectedDetailCompras.get(i).getCantidad();
                valorUnitarioRedondeado = formatearDecimales6(valorUnitario);
                nuevoConcepto.setValorUnitario(valorUnitarioRedondeado);
                //Al ser servicio, siempre es 1
                trasnlado.setBase(formatearDecimales6((Double.parseDouble(valorUnitarioRedondeado) * 1)));
                subTotalFinalTraslados += Double.valueOf(trasnlado.getBase());
                if (ivaProducto.equals("EXENTA")) {
                    trasnlado.setTipoFactor(CTipoFactor.EXENTO);
                } else {
                    trasnlado.setTipoFactor(CTipoFactor.TASA);
                }
                trasnlado.setImpuesto("002");
                if (ivaProducto.equals("EXENTA")) {
                    listaTraslados.setTranslado(trasnlado);
                    impuestos.setTraslados(listaTraslados);
                    tiposTasaOCuota.add("Exento");
                    nuevoConcepto.setObjetoImp("02");
                    listaTrasladosImportesFinales.setTranslado(trasnlado);
                    sumaTrasladosExentos.add(trasnlado.getBase());

                } else {
                    nuevoConcepto.setObjetoImp("02");
                    trasnlado.setTasaOCuota(formatearDecimalesIVA(Double.valueOf(ivaProducto) / 100.00));
                    tiposTasaOCuota.add(String.valueOf(trasnlado.getTasaOCuota()));
                    trasnlado.setImporte(formatearDecimales6(Double.valueOf(trasnlado.getBase()) * (Double.valueOf(trasnlado.getTasaOCuota()))));
                    listaTraslados.setTranslado(trasnlado);
                    impuestos.setTraslados(listaTraslados);
                    listaTrasladosImportesFinales.setTranslado(trasnlado);
                    sumaTrasladosExentos.add("");
                }
            }
            nuevoConcepto.setImporte(Double.valueOf(trasnlado.getBase()));
            nuevoConcepto.setImpuestos(impuestos);
            listasConcepto.setConcepto(nuevoConcepto);
        }*/
        
        //Se llena el nodo CONCEPTO con Gastos
        /*for (int i = 0; i <= selectedDetailCompras.size() - 1; i++) {
            Conceptos.Concepto.Impuestos.Traslados listaTraslados = new Conceptos.Concepto.Impuestos.Traslados();
            String valorUnitarioRedondeado;
            Conceptos.Concepto nuevoConcepto = new Conceptos.Concepto();
            Conceptos.Concepto.Impuestos impuestos = new Conceptos.Concepto.Impuestos();
            Conceptos.Concepto.Impuestos.Traslados.Traslado trasnlado = new Conceptos.Concepto.Impuestos.Traslados.Traslado();
            ProductController productController = new ProductController();
            nuevoConcepto.setClaveProdServ(productController.findProductById(selectedDetailCompras.get(i).getProductId()).getClaveProductoServicio().getCodigo());
            nuevoConcepto.setClaveUnidad(productController.findProductById(selectedDetailCompras.get(i).getProductId()).getClaveUnidad().getClaveUnidad());
            nuevoConcepto.setCantidad(Double.valueOf(selectedDetailCompras.get(i).getCantidad()));
            nuevoConcepto.setDescripcion(selectedDetailCompras.get(i).getProducto());
            if (nuevoComprobante.getTipoDeComprobante().equals(CTipoDeComprobante.P)) {
                nuevoConcepto.setValorUnitario("0.00");
            } else {
                //Calculos individuales si un producto maneja iva o no
                //Se obtiene el iva del producto, al parecer al menos de momento, siempre es 16
                String ivaProducto = "16";
                Double impuestoMultiplicar = 0d;
                if (ivaProducto.equals("16")) {
                    impuestoMultiplicar = 1.16;
                } else if (ivaProducto.equals("11")) {
                    impuestoMultiplicar = 1.11;
                } else if (ivaProducto.equals("8")) {
                    impuestoMultiplicar = 1.08;
                } else if (ivaProducto.equals("0")) {
                    impuestoMultiplicar = 1d;
                } else if (ivaProducto.equals("EXENTA")) {
                    impuestoMultiplicar = 1d;
                }
                Double valorUnitario = (selectedDetailCompras.get(i).getTotal() / impuestoMultiplicar);
                //Al ser servicio, siempre es 1
                valorUnitario = valorUnitario / selectedDetailCompras.get(i).getCantidad();
                valorUnitarioRedondeado = formatearDecimales6(valorUnitario);
                nuevoConcepto.setValorUnitario(valorUnitarioRedondeado);
                //Al ser servicio, siempre es 1
                trasnlado.setBase(formatearDecimales6((Double.parseDouble(valorUnitarioRedondeado) * 1)));
                subTotalFinalTraslados += Double.valueOf(trasnlado.getBase());
                if (ivaProducto.equals("EXENTA")) {
                    trasnlado.setTipoFactor(CTipoFactor.EXENTO);
                } else {
                    trasnlado.setTipoFactor(CTipoFactor.TASA);
                }
                trasnlado.setImpuesto("002");
                if (ivaProducto.equals("EXENTA")) {
                    listaTraslados.setTranslado(trasnlado);
                    impuestos.setTraslados(listaTraslados);
                    tiposTasaOCuota.add("Exento");
                    nuevoConcepto.setObjetoImp("02");
                    listaTrasladosImportesFinales.setTranslado(trasnlado);
                    sumaTrasladosExentos.add(trasnlado.getBase());

                } else {
                    nuevoConcepto.setObjetoImp("02");
                    trasnlado.setTasaOCuota(formatearDecimalesIVA(Double.valueOf(ivaProducto) / 100.00));
                    tiposTasaOCuota.add(String.valueOf(trasnlado.getTasaOCuota()));
                    trasnlado.setImporte(formatearDecimales6(Double.valueOf(trasnlado.getBase()) * (Double.valueOf(trasnlado.getTasaOCuota()))));
                    listaTraslados.setTranslado(trasnlado);
                    impuestos.setTraslados(listaTraslados);
                    listaTrasladosImportesFinales.setTranslado(trasnlado);
                    sumaTrasladosExentos.add("");
                }
            }
            nuevoConcepto.setImporte(Double.valueOf(trasnlado.getBase()));
            nuevoConcepto.setImpuestos(impuestos);
            listasConcepto.setConcepto(nuevoConcepto);
        }*/
        
        

        nuevoComprobante.setConceptos(listasConcepto);
        //Importes totales
        Comprobante40.Impuestos impuestosTotales = new Comprobante40.Impuestos();
        BigDecimal sumaImpuestosTotaltes = new BigDecimal(0);
        Comprobante40.Impuestos.Traslados trasladosTotales = new Comprobante40.Impuestos.Traslados();
        tiposTasaOCuota = sinDuplicados(tiposTasaOCuota);
        Map<Integer, Comprobante40.Impuestos.Traslados.Traslado> mapaTraslados = new HashMap<>();
        for (int i = 0; i <= listaTrasladosImportesFinales.getSizeTraslado() - 1; i++) {
            Conceptos.Concepto.Impuestos.Traslados.Traslado traslado = listaTrasladosImportesFinales.getTrasladoEnLista(i);
            Comprobante40.Impuestos.Traslados.Traslado trasladoFinal = new Comprobante40.Impuestos.Traslados.Traslado();
            trasladoFinal.setBase(BigDecimal.valueOf(Double.parseDouble(traslado.getBase())));
            try {
                trasladoFinal.setImporte(BigDecimal.valueOf(Double.parseDouble(traslado.getImporte())).setScale(6, RoundingMode.HALF_UP));
            } catch (Exception e) {
                trasladoFinal.setImporte(BigDecimal.valueOf(Double.parseDouble(sumaTrasladosExentos.get(i))).setScale(6, RoundingMode.HALF_UP));
            }
            trasladoFinal.setImpuesto(traslado.getImpuesto());
            try {
                trasladoFinal.setTasaOCuota((BigDecimal.valueOf(Double.parseDouble(traslado.getTasaOCuota())).setScale(6, RoundingMode.HALF_UP)));
            } catch (Exception e) {
                trasladoFinal.setTasaOCuota(new BigDecimal(9999));
            }
            trasladoFinal.setTipoFactor(traslado.getTipoFactor());
            trasladoFinal.getBase();
            mapaTraslados.put(i, trasladoFinal);
        }
        for (int i = 0; i <= tiposTasaOCuota.size() - 1; i++) {
            Comprobante40.Impuestos.Traslados.Traslado trasladoFinal = new Comprobante40.Impuestos.Traslados.Traslado();
            BigDecimal sumaImporte = new BigDecimal(0);
            BigDecimal sumaBase = new BigDecimal(0);
            BigDecimal tasaOCuota = new BigDecimal(0);
            CTipoFactor tipoFactor = null;
            String impuesto = null;
            Integer validadorExento = 0;
            for (int j = 0; j <= mapaTraslados.size() - 1; j++) {
                if (mapaTraslados.get(j).getTasaOCuota().doubleValue() == 9999.0 && tiposTasaOCuota.get(i).equals("Exento")) {
                    sumaBase = sumaBase.add(mapaTraslados.get(j).base);
                    impuesto = mapaTraslados.get(j).getImpuesto();
                    validadorExento = 1;
                } else if (tiposTasaOCuota.get(i).equals("Exento")) {
                    System.out.println("Ignora");
                } else if (mapaTraslados.get(j).getTasaOCuota().doubleValue() == Double.valueOf(tiposTasaOCuota.get(i))) {
                    sumaBase = sumaBase.add(mapaTraslados.get(j).base);
                    sumaImporte = sumaImporte.add(mapaTraslados.get(j).getImporte());
                    tasaOCuota = (mapaTraslados.get(j).getTasaOCuota()).setScale(6, RoundingMode.HALF_UP);
                    tipoFactor = (mapaTraslados.get(j).getTipoFactor());
                    impuesto = mapaTraslados.get(j).getImpuesto();
                }
            }
            if (validadorExento == 0) {
                trasladoFinal.setBase(sumaBase.setScale(2, RoundingMode.HALF_UP));
                trasladoFinal.setImporte(sumaImporte.setScale(2, RoundingMode.HALF_UP));
                trasladoFinal.setTasaOCuota(tasaOCuota.setScale(6));
                trasladoFinal.setTipoFactor(tipoFactor);
                trasladoFinal.setImpuesto(impuesto);
                trasladosTotales.setTranslado(trasladoFinal);
                sumaImpuestosTotaltes = sumaImpuestosTotaltes.add(sumaImporte);
                impuestosTotales.setTraslados(trasladosTotales);
            } else {
                trasladoFinal.setBase(sumaBase.setScale(2, RoundingMode.HALF_UP));
                trasladoFinal.setImpuesto(impuesto);
                trasladoFinal.setTipoFactor(tipoFactor.EXENTO);
                trasladosTotales.setTranslado(trasladoFinal);
                impuestosTotales.setTraslados(trasladosTotales);
            }

        }

        BigDecimal subTotal = new BigDecimal(BigInteger.ZERO);
        for (int c = 0; c <= listaTrasladosImportesFinales.getSizeTraslado() - 1; c++) {
            Conceptos.Concepto.Impuestos.Traslados.Traslado trasladoSumaSubtotal = listaTrasladosImportesFinales.getTrasladoEnLista(c);
            BigDecimal bd = new BigDecimal(trasladoSumaSubtotal.getBase());
            subTotal = subTotal.add(bd);
        }
        nuevoComprobante.setSubTotal(Double.valueOf(formatearDecimales(subTotalFinalTraslados)));
        impuestosTotales.setTotalImpuestosTrasladados(sumaImpuestosTotaltes.setScale(2, RoundingMode.HALF_UP));
        nuevoComprobante.setImpuestos(impuestosTotales);
        //Se llena el "sello" de prueba
        nuevoComprobante.setSello(""); //Se asigna en el timbrado
        Comprobante40.Complemento complemento = new Comprobante40.Complemento();
        nuevoComprobante.setComplemento(complemento);
        OutputStream nombreDoc = new FileOutputStream(nuevoComprobante.getSerie() + ".xml");
        jaxbObjectToXML(nuevoComprobante, nombreDoc);
        generarCadenaOriginal(nuevoComprobante.getSerie() + ".xml", dataLocation);
        nuevoComprobante.setSello(sellocfdi);
        File xml = new File(nuevoComprobante.getSerie() + ".xml");
        try {
            if (xml.delete()) {
                System.out.println(xml.getName() + " deleted");
            } else {
                System.out.println("failed");
            }
        } catch (Exception e) {
            System.out.println("Error: " + e);
        }
        OutputStream docConSello = new FileOutputStream(nuevoComprobante.getSerie() + ".xml");
        jaxbObjectToXML(nuevoComprobante, docConSello);
        File xmlSello = new File(nuevoComprobante.getSerie() + ".xml");
        /*respuesta = obtenerDatos.conexionWS(xmlSello);
        if (respuesta.size() <= 2) {
            String[] errorSplit = respuesta.get(0).split("\\.");
            String respuestaFormateada = "";
            for (int j = 0; j <= errorSplit.length - 1; j++) {
                respuestaFormateada = respuestaFormateada + "" + errorSplit[j] + "\n";
            }
            JOptionPane.showMessageDialog(null, respuestaFormateada);
            int i = 0;
            xml = new File(nuevoComprobante.getSerie() + ".xml");
            xml.delete();
            return i;
        }
        xmlSello.deleteOnExit();
        Comprobante40.Complemento.TimbreFiscalDigital timbreFiscal = new Comprobante40.Complemento.TimbreFiscalDigital();
        timbreFiscal.setXmlnsFtd("http://www.sat.gob.mx/TimbreFiscalDigital");
        timbreFiscal.setXsiSchemaLocation("http://www.sat.gob.mx/TimbreFiscalDigital http://www.sat.gob.mx/sitio_internet/cfd/TimbreFiscalDigital/TimbreFiscalDigitalv11.xsd");
        timbreFiscal.setVersion(respuesta.get(0));
        timbreFiscal.setUuid(respuesta.get(1));
        timbreFiscal.setFechaTimbrado(respuesta.get(3));
        timbreFiscal.setRfcProvCertif(respuesta.get(4));
        timbreFiscal.setSelloCFD(sellocfdi);
        timbreFiscal.setNoCertificadoSAT(respuesta.get(5));
        timbreFiscal.setSelloSAT(respuesta.get(2));
        complemento.setTimbreFiscal(timbreFiscal);
        nuevoComprobante.setComplemento(complemento);
        OutputStream xmlTimbrado = new FileOutputStream(respuesta.get(1) + ".xml");
        jaxbObjectToXML(nuevoComprobante, xmlTimbrado);
        //Se inserta en la base de datos factura;
        factura.setSerie(nuevoComprobante.getSerie());
        factura.setFolio(nuevoComprobante.getFolio());
        factura.setUuid(respuesta.get(1));
        factura.setSelloSat(respuesta.get(2));
        factura.setSelloEmisor(sellocfdi);
        factura.setCertificadoContribuyente(numeroCertificado);
        Date fecha = sdf.parse(respuesta.get(3));
        factura.setFechaEmision(new Timestamp(fecha.getTime()));
        factura.setRfcEmisor(respuesta.get(4));
        factura.setNumeroCertificado(respuesta.get(5));
        factura.setQr(respuesta.get(6));
        factura.setCadenaOriginal(respuesta.get(7));

        switch (formaPago) {
            case "01":
                factura.setTipoPago("Efectivo");
                break;
            case "02":
                factura.setTipoPago("Cheque nominativo");
                break;
            case "03":
                factura.setTipoPago("Transferencia electrónica");
                break;
            case "04":
                factura.setTipoPago("Tarjeta de crédito");
                break;
            case "05":
                factura.setTipoPago("Monedero electrónico");
                break;
            case "06":
                factura.setTipoPago("Dinero electrónico");
                break;
            case "07":
                factura.setTipoPago("Tarjetas digitales");
                break;
            case "08":
                factura.setTipoPago("Vales de despensa");
                break;
            case "09":
                factura.setTipoPago("Bienes");
                break;
            case "10":
                factura.setTipoPago("Servicio");
                break;
            case "11":
                factura.setTipoPago("Por cuenta de tercero");
                break;
            case "12":
                factura.setTipoPago("Dación en pago");
                break;
            case "13":
                factura.setTipoPago("Pago por subrogación");
                break;
            case "14":
                factura.setTipoPago("Pago por consignación");
                break;
            case "15":
                factura.setTipoPago("Condonación");
                break;
            case "16":
                factura.setTipoPago("Cancelación");
                break;
            case "17":
                factura.setTipoPago("Compensación");
                break;
            case "23":
                factura.setTipoPago("Novación");
                break;
            case "24":
                factura.setTipoPago("Confusión");
                break;
            case "25":
                factura.setTipoPago("Remisión de deuda");
                break;
            case "26":
                factura.setTipoPago("Prescripción o caudidad");
                break;
            case "27":
                factura.setTipoPago("A satisfacción del acreedor");
                break;
            case "28":
                factura.setTipoPago("Tarjeta de débito");
                break;
            case "29":
                factura.setTipoPago("Tarjeta de servicios");
                break;
            case "30":
                factura.setTipoPago("Aplicación de anticipos");
                break;
            case "98":
                factura.setTipoPago("NA");
                break;
            case "99":
                factura.setTipoPago("Por definir");
                break;
        }

        switch (usoCFDI) {
            case G_01:
                factura.setUsoCFDI("Adquisición de mercancías");
                break;
            case G_02:
                factura.setUsoCFDI("Devoluciones, Descuentos o bonificaciones");
                break;
            case G_03:
                factura.setUsoCFDI("Gastos en general");
                break;
            case I_01:
                factura.setUsoCFDI("Construcciones");
                break;
            case I_02:
                factura.setUsoCFDI("Mobiliario y equipo de oficina por inversiones");
                break;
            case I_03:
                factura.setUsoCFDI("Equipo de transporte");
                break;
            case I_04:
                factura.setUsoCFDI("Equipo de cómputo y accesorios");
                break;
            case I_05:
                factura.setUsoCFDI("Dados, troqueles, moldes, matrices y herramental");
                break;
            case I_06:
                factura.setUsoCFDI("Comunicaciones telefónicas");
                break;
            case I_07:
                factura.setUsoCFDI("Comunicaciones satelitales");
                break;
            case I_08:
                factura.setUsoCFDI("Otra maquinaria y equipo");
                break;
            case D_01:
                factura.setUsoCFDI("Honorarios médicos, dentales y gastos hospitalarios");
                break;
            case D_02:
                factura.setUsoCFDI("Gastos médicos por incapacidad o discapacidad");
                break;
            case D_03:
                factura.setUsoCFDI("Gastos funerales");
                break;
            case D_04:
                factura.setUsoCFDI("Donativos");
                break;
            case D_05:
                factura.setUsoCFDI("Intereses reales efectivamente pagados por créditos hipotecarios (casa habitación)");
                break;
            case D_06:
                factura.setUsoCFDI("Aportaciones voluntarias al SAR");
                break;
            case D_07:
                factura.setUsoCFDI("Primas por seguros de gastos médicos");
                break;
            case D_08:
                factura.setUsoCFDI("Gastos de transportación escolar obligatoria");
                break;
            case D_09:
                factura.setUsoCFDI("Depósitos en cuentas para el ahorro, primas que tengan como base planes de pensiones");
                break;
            case D_10:
                factura.setUsoCFDI("Pagos por servicios educativos (colegiaturas)");
                break;
            case P_01:
                factura.setUsoCFDI("Por definir");
                break;
            case S_01:
                factura.setUsoCFDI("Sin efectos fiscales");
                break;
            case CP_01:
                factura.setUsoCFDI("Pagos");
                break;
            case CN_01:
                factura.setUsoCFDI("Nómina");
                break;
        }
        factura.setCondicionPago(condicionPago);
        factura.setTipoComprobante(nuevoComprobante.getTipoDeComprobante().valor);
        factura.setMetodoPago(nuevoComprobante.getMetodoPago().value());
        //Se guarda la factura;
        controladorFactura.guardarRegistro(factura);
        factura.setId(controladorFactura.getUltimoPk());
        venta.setFactura(factura);
        //Se guarda la venta con el nuevo id

        controladorVenta.updateIdFactura(venta);
        File xmlTimbre = new File(respuesta.get(1) + ".xml");
        //Se hace un blob con el XML     
        try {
            FileInputStream xmlBlob = new FileInputStream(xmlTimbre);
            blobXml = new DatoArchivo(xmlBlob, (int) xmlTimbre.length());
            System.out.println(blobXml.getLongitud());
        } catch (IOException ex) {
            Logger.getLogger(IProducto.class.getName()).log(Level.SEVERE, null, ex);
        }

        factura.setXmlData(blobXml);
        controladorFactura.updateXmlFactura(factura);
        //IMAGEN
        byte[] decodeqrCode = org.apache.commons.codec.binary.Base64.decodeBase64(factura.getQr().getBytes());
        ByteArrayInputStream bis = new ByteArrayInputStream(decodeqrCode);
        BufferedImage bImage2 = ImageIO.read(bis);
        ImageIO.write(bImage2, "jpg", new File("qr.jpg"));
        File imagen = new File("qr.jpg");
        String qrImage = imagen.getAbsolutePath();

        JasperReport jReport = (JasperReport) JRLoader.loadObject(getClass().getResource("/jasperReports/factura.jasper"));
        JasperReport jReportDesc = (JasperReport) JRLoader.loadObject(getClass().getResource("/jasperReports/facturaDesc.jasper"));
        Map<String, Object> parametros = new HashMap<>();
        parametros.put("idVenta", idVenta);
        parametros.put("qrImage", qrImage);

        File logo = new File("C:/PuntoVenta/logo_empresa.jpg");
        if (!logo.exists()) {
            logo = new File("C:/Program Files/PuntoVentaCROV/logomenu.png");
        }
        parametros.put("logo", logo.getAbsolutePath());

        NumerosLetras numeroLetras = new NumerosLetras();

        parametros.put("numeroLetras", numeroLetras.Convertir(venta.getTotal() + "", true));
        if (AppConfig.getAct_descripcion_facturacion() == 0) {
            JasperPrint jPrint = JasperFillManager.fillReport(jReport, parametros, BaseConexion.getConexion());
            JasperExportManager.exportReportToPdfFile(jPrint, respuesta.get(1) + ".pdf");
            JasperViewer jViewer = new JasperViewer(jPrint, false);
            jViewer.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
            jViewer.setVisible(true);
        } else {
            JasperPrint jPrint = JasperFillManager.fillReport(jReportDesc, parametros, BaseConexion.getConexion());
            JasperExportManager.exportReportToPdfFile(jPrint, respuesta.get(1) + ".pdf");
            JasperViewer jViewer = new JasperViewer(jPrint, false);
            jViewer.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
            jViewer.setVisible(true);
        }

        //Se envia el correo electronico con el xml
        ArrayList<File> documentosEnviados = new ArrayList<>();
        File pdfFactura = new File(respuesta.get(1) + ".pdf");
        documentosEnviados.add(xmlTimbre);
        documentosEnviados.add(pdfFactura);
        //documentosEnviados.add(xml);
        try {

            if (ServidorCorreo.getCorreoElectronico().contains("@gmail.com")) {
                ServidorCorreo.enviarGmail("Estimad@ " + cliente.getRazonSocial() + ". Este correo es enviado de manera automatica\n"
                        + "para indicarle que su factura ha sido realizada con exito.", "Factura " + factura.getUuid() + " - PuntoDeVentaCROV", cliente.getEmail(), documentosEnviados);
            } else if (ServidorCorreo.getCorreoElectronico().contains("@hotmail.com")) {
                ServidorCorreo.enviarHotmail("Estimad@ " + cliente.getRazonSocial() + ". Este correo es enviado de manera automatica\n"
                        + "para indicarle que su factura ha sido realizada con exito.", "Factura " + factura.getUuid() + " - PuntoDeVentaCROV", cliente.getEmail(), documentosEnviados);

            }

        } catch (Exception e) {
            JOptionPane.showMessageDialog(null, "No se pudo enviar el correo con la factura al cliente. En caso de necesitarlo: /n Configurarlo en catalogo, configuracion o revisar el correo del cliente.");
        }

        JOptionPane.showMessageDialog(null, "Factura con nombre: " + respuesta.get(1) + " creada con exito.");
        int i = 1;
        ControladorFolio controladorFolio = new ControladorFolio();
        folio.setFolio(folio.getFolio() + folio.getIncremento());
        controladorFolio.actualizarNumeroFolio(folio);
        xmlTimbre.delete();
        pdfFactura.delete();
*/
        int i =1;
        return i;

    }

    private static void jaxbObjectToXML(Comprobante40 comprobante40, OutputStream nombreDoc) {
        try {
            JAXBContext jaxbContext = JAXBContext.newInstance(Comprobante40.class);
            Marshaller jaxbMarshaller = jaxbContext.createMarshaller();

            jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); // To format XML

            //Print XML String to Console
            jaxbMarshaller.marshal(comprobante40, nombreDoc);
        } catch (JAXBException e) {
            e.printStackTrace();
        }
    }
    
    public ArrayList<String> sinDuplicados(ArrayList<String> arreglo) {
        ArrayList<String> sinDuplicados = new ArrayList<>();
        Set<String> limpio = new HashSet<String>(arreglo);
        for (String s : limpio) {
            sinDuplicados.add(s);
        }
        return sinDuplicados;
    }

    public static String formatearDecimales(Double numero) {
        DecimalFormat formato = new DecimalFormat("0.00");
        return formato.format(numero);

    }

    public static String formatearDecimales6(Double numero) {
        DecimalFormat formato = new DecimalFormat("0.000000");
        return formato.format(numero);

    }

    public static String formatearDecimalesIVA(Double numero) {
        DecimalFormat formato = new DecimalFormat("0.000000");
        return formato.format(numero);

    }

    public static BigDecimal formatearBigDecimal(Double numero) {
        BigDecimal bd = new BigDecimal(numero);
        BigDecimal roundOff = bd.setScale(2, RoundingMode.HALF_UP);
        return roundOff;
    }

    public void generarCadenaOriginal(String nombre, Location dataLocation) throws TransformerConfigurationException, TransformerException, FileNotFoundException, GeneralSecurityException, IOException {
        String filePath= FacesContext.getCurrentInstance().getExternalContext().getRealPath("/resources/cadenaoriginal_4_0.xslt");        
        File xslt = new File(filePath);
        StreamSource sourceXSL = new StreamSource(xslt);
        File cfdi = new File(nombre);
        StreamSource sourceXML = new StreamSource(cfdi);
        TransformerFactory tFactory = TransformerFactory.newInstance();
        Transformer transformer = tFactory.newTransformer(sourceXSL);
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        transformer.transform(sourceXML, new StreamResult(bos));
        byte[] cadenaOriginal = bos.toByteArray();
        InputStream keyFileInput = initS3(nombre, sellocfdi, nombre, nombre, dataLocation);
        PKCS8Key pkcs8 = new PKCS8Key(keyFileInput, dataLocation.getCertificatePassword().toCharArray());
        KeyFactory privateKeyFactory = KeyFactory.getInstance("RSA");
        PKCS8EncodedKeySpec pkcs8Encoded = new PKCS8EncodedKeySpec(pkcs8.getDecryptedBytes());
        PrivateKey privateKey = privateKeyFactory.generatePrivate(pkcs8Encoded);
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initSign(privateKey);
        signature.update(cadenaOriginal);
        sellocfdi = new String(Base64.encodeBase64(signature.sign()), "UTF-8");
        System.out.println("------------------ Cadena Original: " + bos.toString());
        System.out.println("---------Firma: " + sellocfdi);

    }
    
    public InputStream initS3(String accessKey, String secretKey, String region, String bucket, Location location) {
       /* AWSCredentials credentials =new BasicAWSCredentials(
                accessKey,
                secretKey
        );*/

     /*   AmazonS3 s3Client = AmazonS3ClientBuilder
                .standard()
                .withCredentials(new AWSStaticCredentialsProvider(credentials))
                .withRegion(region)
                .build();

        if (s3Client.doesBucketExistV2(bucket)) {
            
            return null;
        }
        S3Object s3object = s3Client.getObject(bucket, location.getCertificate());
        S3ObjectInputStream inputStream = s3object.getObjectContent();*/
        return null;
    }
    

}
