/*
 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
 * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
 */
package com.fp.frontend.controller.armas.solicitud;

import com.fp.common.logger.APPLogger;
import com.fp.dto.AbstractDataTransport;
import com.fp.frontend.controller.AbstractController;
import com.fp.frontend.controller.armas.parametros.CentroControlArmasController;
import com.fp.frontend.controller.pcustomer.PersonAddressController;
import com.fp.frontend.controller.pcustomer.PersonDetailController;
import com.fp.frontend.controller.pcustomer.PersonPhoneController;
import com.fp.frontend.controller.pgeneral.gene.CityController;
import com.fp.frontend.controller.pgeneral.gene.ParametersController;
import com.fp.persistence.commondb.PersistenceHelper;
import com.fp.persistence.commondb.data.SessionData;
import com.fp.persistence.commondb.data.ThreadFacade;
import com.fp.persistence.parmas.param.TarmCentroControl;
import com.fp.persistence.parmas.param.TarmTramite;
import com.fp.persistence.parmas.soli.TarmInvoiceHistory;
import com.fp.persistence.parmas.soli.TarmSolicitud;
import com.fp.persistence.parmas.soli.TarmSolicitudTramite;
import com.fp.persistence.pcustomer.gene.TcustPersonAddress;
import com.fp.persistence.pcustomer.gene.TcustPersonDetail;
import com.fp.persistence.pcustomer.gene.TcustPersonPhone;
import com.fp.persistence.pgeneral.gene.TgeneCity;
import com.fp.persistence.pgeneral.gene.TgeneParameters;
import com.fp.persistence.pgeneral.safe.TsafeUserDetail;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;
 
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.openide.util.Exceptions;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

/**
 * CLASE PARA GENERACION DE XML
 * @author developer2
 */
@ManagedBean
@ViewScoped
public class FacturaController extends AbstractController<AbstractDataTransport>{
    private static final long serialVersionUID = -4049698904561227471L;
    
    private EntityManagerFactory emf;
    
    private final void crearManager() {
        try {
            if (emf == null) {
                Map<String, Object> configOverrides = new HashMap<String, Object>();
                configOverrides.put("hibernate.ejb.cfgfile", "hibernateFlipMapping.cfg.xml");
                emf = Persistence.createEntityManagerFactory("local2", configOverrides);
            }
            SessionData sessionData = new SessionData();
            sessionData.setCompany(1);
            sessionData.setIsEjb(Boolean.FALSE);
            ThreadFacade.setSaveRequest(sessionData);
        } catch (Exception e) {
            APPLogger.getLogger().error(e);
        }
    }
    
    
    public FacturaController() throws Exception{
        super(AbstractDataTransport.class);
    }
    
    
    @ManagedProperty(value = "#{iv}")
    private InvoiceHistoryController iv;
    
    @PostConstruct
    public void postConstruct(){
        
   
    }
    
    
    /** 
     *Codigo de GENERACION DE XML DE FACTURAS
     */ 

    public void crearAgregarHijo(Document doc, Element padre, String nombreElemento, String textoElemento) {
        Element hijo = crearElemento(doc, nombreElemento, textoElemento);
        agregarHijoPadre(doc, padre, hijo);
    }

    public void crearAtributo(Document doc, Element elemento, String nombreAtributo, String valorAtributo) {
        Attr attr = doc.createAttribute(nombreAtributo);
        attr.setValue(valorAtributo);
        elemento.setAttributeNode(attr);
    }

    public void crearAgregarHijoAtributo(Document doc, Element padre, String nombreElemento, String textoElemento, String nombreAtributo, String textoAtributo) {
        Element hijo = crearElemento(doc, nombreElemento, textoElemento);
        crearAtributo(doc, hijo, nombreAtributo, textoAtributo);
        agregarHijoPadre(doc, padre, hijo);
    }

    public Element crearElemento(Document doc, String nombreElemento, String textoElemento) {
        Element elemento1 = doc.createElement(nombreElemento);
        elemento1.setTextContent(textoElemento);
        return elemento1;
    }

    public Element crearElementoSinTexto(Document doc, String nombreElemento) {
        Element elemento1 = doc.createElement(nombreElemento);
        return elemento1;
    }

    public void agregarHijoPadre(Document doc, Element padre, Element hijo) {
        padre.appendChild(hijo);

    }
    
    /**
     *ACTUALIZAR SECUENCIA DE CENTRO DE CONTROL
     */
    public void actualizarSecuenciaCcontrol(TarmCentroControl centroControl, CentroControlArmasController cac) throws Exception{
        centroControl.setSecuenciafacturacion(centroControl.getSecuenciafacturacion()+1);
        cac.update(centroControl);
        cac.save();
    }
    /**
     * Por cuestinoes de tiempo se desarrollo query nativo con entityManager, misma logica que schedulexml
     */
    public void guardarAuditoria(String csoli,String user, String solicitudNumber, String tramiteNumber,String path) throws IOException, Exception{
            Query q = null;
            String insert = String.format("INSERT INTO TARMINVOICEHISTORY\n" +
                        "(USERCODE, REGISTRATIONDATE, CSOLICITUD, SOLICITUDNUMBER, TRAMITENUMBER, PATHFILE, CONTENTFILE)\n" +
                        "VALUES ('%s', now(), '%s', '%s', '%s', '%s','%s')", user, csoli, solicitudNumber, tramiteNumber, path, obtenerContenidoArchivo(path));
            int ejecucion = this.callerhelper.executeNativeQuery(insert);
            System.out.println("Numero de filas afectadas: "+ejecucion);
    
    }
    
    /**
     *Buscar direccion de la persona si es la principal (Y)
     */
    public TcustPersonAddress setDireccionPrincipal(TcustPersonAddress direccion, List<TcustPersonAddress> lstdireccionDomicilio){
        if (lstdireccionDomicilio != null && !lstdireccionDomicilio.isEmpty()) {
            for (TcustPersonAddress tcustPersonAddress : lstdireccionDomicilio) {
                if (tcustPersonAddress.getPrincipal().equalsIgnoreCase("Y")) {
                    direccion = tcustPersonAddress;
                    break;
                }
            }
        }
        return direccion;
    }
    /**
     * Buscar el telefono mas principal segun el numero secuencial establecido en addresNumber
     */
    public TcustPersonPhone buscarTelefonoPrincipal(List<TcustPersonPhone> lstTelefonos){
        int masBajo = 0;
        Integer index = null;

        if (lstTelefonos != null && !lstTelefonos.isEmpty()) {
            for (int j = 0; j < lstTelefonos.size(); j++) {
                if (j == 0) {
                    masBajo = lstTelefonos.get(j).getAddressnumber();
                    index = j;
                } else {
                    if (lstTelefonos.get(j).getAddressnumber() < masBajo) {
                        masBajo = lstTelefonos.get(j).getAddressnumber();
                        index = j;
                    }
                }
            }
        }
            return lstTelefonos.get(index) ;
    }
    /**
     * Generar el detalle 1 de la factura
     */
    public void generarDetalle1(Document doc, Element detalle1, String codigoPrincipal, String descripcion, Integer cantidad, Double precioUnitario, Double precioTotalSinImpuestos){
        crearAgregarHijo(doc, detalle1, "codigoPrincipal", codigoPrincipal);
        crearAgregarHijo(doc, detalle1, "descripcion", descripcion);
        crearAgregarHijo(doc, detalle1, "cantidad", cantidad + "");
        crearAgregarHijo(doc, detalle1, "precioUnitario", precioUnitario.toString());
        crearAgregarHijo(doc, detalle1, "descuento", "0.00");
        crearAgregarHijo(doc, detalle1, "precioTotalSinImpuesto", precioTotalSinImpuestos.toString());
    }
    /**
     *Generar el detalle de los custodios 
     */
    public void generarCustodio(Document doc, TgeneParameters tCustodio, TarmSolicitud solicitud, TarmSolicitudTramite solicitudTramite, String impuesto, Integer porcentajeDescuento, Element detalles ){
        Element detalle2 = crearElementoSinTexto(doc, "detalle");
            String codigoPrincipal2 = tCustodio.getNumbervalue().toString().contains(".") 
                    ? tCustodio.getNumbervalue().toString().split("\\.")[0] : tCustodio.getNumbervalue().toString() ;            int numeroDias = solicitud != null && solicitud.getNumerodiascustodios() != null ? solicitud.getNumerodiascustodios() : null;
            int numeroCustodios=solicitud != null ? solicitud.getNumerocustodios() : null;

            String descripcion2 = String.format(tCustodio.getTextvalue(), numeroDias);
            Double precioUnitario2 = solicitudTramite.getValorcustodios().doubleValue()/ numeroCustodios;
            Double precioTotalSinImpuestos2 = solicitudTramite.getValorcustodios().doubleValue() ;

            crearAgregarHijo(doc, detalle2, "codigoPrincipal", codigoPrincipal2);
            crearAgregarHijo(doc, detalle2, "descripcion", descripcion2);
            crearAgregarHijo(doc, detalle2, "cantidad", numeroCustodios + "");
            crearAgregarHijo(doc, detalle2, "precioUnitario", precioUnitario2.toString());
            crearAgregarHijo(doc, detalle2, "descuento", "0.00");
            crearAgregarHijo(doc, detalle2, "precioTotalSinImpuesto", precioTotalSinImpuestos2.toString());

            Element impuestoItem2 = crearElementoSinTexto(doc, "impuestoItem");
            Element impueste2 = crearElementoSinTexto(doc, "impuesto");
            crearAgregarHijo(doc, impueste2, "impuesto", impuesto);
            crearAgregarHijo(doc, impueste2, "Porcentaje", porcentajeDescuento + "");
            crearAgregarHijo(doc, impueste2, "baseImponible", precioTotalSinImpuestos2.toString());
            agregarHijoPadre(doc, impuestoItem2, impueste2);
            agregarHijoPadre(doc, detalle2, impuestoItem2);
            agregarHijoPadre(doc, detalles, detalle2);
    
    }
    
    
    public File sacarFactura(String codigoSolicitud, File carpetaBase, TsafeUserDetail tsafeUserDetail) throws Exception {
        CentroControlArmasController cac = new CentroControlArmasController();
        TgeneParameters tCustodio = ParametersController.find("CUSTODIOSFACTURA", "1");
        
        String noDisponible = ""; /**SE SUELE UTILIZAR SI ES QUE SE REQUIERE UN MENSAJE EN DATOS VACIOS*/
        DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
        //Elemento raíz
        Document doc = docBuilder.newDocument();
        Element factura = doc.createElement("factura");
        doc.appendChild(factura);

        TarmSolicitudTramite solicitudTramite = SolicitudTramiteController.findByCSolicitud(codigoSolicitud);
        TarmSolicitud solicitud = SolicitudController.findSolicitudxcodsolicitud(codigoSolicitud);
        Integer personCode = solicitud.getPersoncode();
        TcustPersonDetail persona = PersonDetailController.find(personCode.toString());
        TgeneParameters parametroRUC = ParametersController.find("RUCCOMACO", "1");
        TarmTramite tTramite = TarmTramiteController.findSimple(solicitud.getCtramite().toString());
        String rucComaco = parametroRUC.getTextvalue();
        crearAgregarHijo(doc, factura, "ruc", rucComaco);

        TarmCentroControl centroControl = CentroControlArmasController.findPorCodigo(solicitud.getCcentrocontrol());
        String serie = centroControl != null && centroControl.getPuntofacturacion() != null ? 
                centroControl.getPuntofacturacion().replace("-", "") : "";
        crearAgregarHijo(doc, factura, "secuencia",String.format("%09d", centroControl.getSecuenciafacturacion()));
        /**
         * ACTUALIZAR LA SECUENCIA DEL CENTRO DE CONTROL
         */
        actualizarSecuenciaCcontrol(centroControl, cac);
        crearAgregarHijo(doc, factura, "serie", serie);
        
        //Fecha de emision
        SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");
        String fechaEmision = sdf.format(Calendar.getInstance().getTime());
        crearAgregarHijo(doc, factura, "fecha", fechaEmision);
        
        /**
         * ============================= DATOS DE PERSONA
         */
        crearAgregarHijo(doc, factura, "tipoIdComprador", persona.getIdentificationcatalog());
        crearAgregarHijo(doc, factura, "razonSocialComprador", persona.getName());
        crearAgregarHijo(doc, factura, "identificacionComprador", persona.getIdentification());

        /**
         * *********************** Direccion
         */
        TcustPersonAddress direccionDomicilio = null;
        List<TcustPersonAddress> lstdireccionDomicilio = PersonAddressController.findByPersonCodeList(personCode.toString(), "1");
        
        direccionDomicilio = setDireccionPrincipal(direccionDomicilio, lstdireccionDomicilio);
        
        List<TcustPersonAddress> lstCorreos = PersonAddressController.findByPersonCodeList(personCode.toString(), "3");

        TcustPersonAddress correo = null;
        /** ====================== buscar por menor addresNumber  */
        correo = lstCorreos != null || !lstCorreos.isEmpty() ? lstCorreos.get(0) : null;

        TcustPersonPhone telefono = null;
        List<TcustPersonPhone> lstTelefonos = PersonPhoneController.findAll(personCode.toString(), "1");
        telefono = buscarTelefonoPrincipal(lstTelefonos);
        
        PersonPhoneController.find(personCode.toString(), "1");
        Double valorAPagar = solicitudTramite.getValorapagar().doubleValue();
        crearAgregarHijo(doc, factura, "direccionComprador", direccionDomicilio != null ? direccionDomicilio.getAddress() : noDisponible);
        crearAgregarHijo(doc, factura, "totalSinImpuestos", valorAPagar.toString());
        crearAgregarHijo(doc, factura, "totalDescuento", "0.00");
        /**
         * ================== impuestoTotal ================
         */
        String impuesto = "IVA";
        int porcentajeDescuento = 0;

        Element impuestoTotal = crearElementoSinTexto(doc, "impuestoTotal");
        Element totalImpuesto1 = crearElementoSinTexto(doc, "totalImpuesto");
        Element totalImpuesto2 = crearElementoSinTexto(doc, "totalImpuesto");

        crearAgregarHijo(doc, totalImpuesto1, "codigo", impuesto);
        crearAgregarHijo(doc, totalImpuesto1, "Porcentaje", porcentajeDescuento + "");
        crearAgregarHijo(doc, totalImpuesto1, "baseImponible", valorAPagar.toString());


        crearAgregarHijo(doc, totalImpuesto2, "baseImponible", impuesto);
        crearAgregarHijo(doc, totalImpuesto2, "Porcentaje", "12");
        crearAgregarHijo(doc, totalImpuesto2, "baseImponible", "0.00");
        agregarHijoPadre(doc, impuestoTotal, totalImpuesto1);
        agregarHijoPadre(doc, impuestoTotal, totalImpuesto2);
        agregarHijoPadre(doc, factura, impuestoTotal);
        crearAgregarHijo(doc, factura, "totalFactura", valorAPagar.toString());
        /**
         * ========================= Detalles ================================
         */

        String []servicios = tTramite.getServicio() != null ? tTramite.getServicio().split("-"):null;
        
        String codigoPrincipal = servicios != null ? servicios[0]: ""; /**IMPORTANTE REVISAR*/
        String descripcion = servicios != null ? servicios[1]: "";
        int cantidad = 1; /**Cantidad de productos en solicitud*/
        Double precioUnitario = solicitudTramite.getValortramitearmas().doubleValue();
        Double precioTotalSinImpuestos = precioUnitario * cantidad;
        Element detalles = crearElementoSinTexto(doc, "detalles");
        Element detalle1 = crearElementoSinTexto(doc, "detalle");
        
        generarDetalle1(doc, detalle1, codigoPrincipal, descripcion, cantidad, precioUnitario, precioTotalSinImpuestos);

        Element impuestoItem = crearElementoSinTexto(doc, "impuestoItem");
        Element impueste = crearElementoSinTexto(doc, "impuesto");

        crearAgregarHijo(doc, impueste, "impuesto", impuesto);
        crearAgregarHijo(doc, impueste, "Porcentaje", porcentajeDescuento + "");
        crearAgregarHijo(doc, impueste, "baseImponible", precioTotalSinImpuestos + "");
        agregarHijoPadre(doc, impuestoItem, impueste);
        agregarHijoPadre(doc, detalle1, impuestoItem);
        agregarHijoPadre(doc, detalles, detalle1);

        /**
         * **** custodios
         */
        if (solicitudTramite.getValorcustodios() != null && solicitudTramite.getValorcustodios().doubleValue() > 0) {
            generarCustodio(doc, tCustodio, solicitud, solicitudTramite, impuesto, porcentajeDescuento, detalles);

        }
        agregarHijoPadre(doc, factura, detalles);

        /**
         * ========================= Pagos ================================
         */
        Element pagos = crearElementoSinTexto(doc, "pagos");
        Element pago = crearElementoSinTexto(doc, "pago");
        /**
         * formaPago: de momento, tocaria ver los nemonicos a futuro para pago con tarjeta
         */
        String formaPago = "EF";
        
        Double totalPagar = valorAPagar;
        crearAgregarHijo(doc, pago, "formaPago", formaPago);
        crearAgregarHijo(doc, pago, "total", totalPagar.toString());
        agregarHijoPadre(doc, pagos, pago);
        agregarHijoPadre(doc, factura, pagos);
        /**
         * ========================= INFOAdicional ========================
         */
        String mail = correo != null ? correo.getAddress() : noDisponible;
        String telefonoFijo = telefono != null ? telefono.getPhonenumber() : noDisponible;
        if (telefonoFijo.contains("-")) {
            telefonoFijo = telefonoFijo.split("-")[1];
        }
        TgeneCity Tciudad = null;
        if (direccionDomicilio != null) {
            Tciudad = CityController.findOnlyOne(direccionDomicilio.getCountrycode(),
                    direccionDomicilio.getProvincecode(), direccionDomicilio.getCantoncode(), direccionDomicilio.getCitycode());
        }

        String ciudad = Tciudad != null ? Tciudad.getDescription() : noDisponible;
        Element infoAdicional = crearElementoSinTexto(doc, "infoAdicional");
        crearAgregarHijoAtributo(doc, infoAdicional, "campoAdicional", mail, "nombre", "Mail");
        crearAgregarHijoAtributo(doc, infoAdicional, "campoAdicional", telefonoFijo, "nombre", "Telefono");
        crearAgregarHijoAtributo(doc, infoAdicional, "campoAdicional", ciudad, "nombre", "Ciudad");
        agregarHijoPadre(doc, factura, infoAdicional);

        //Se escribe el contenido del XML en un archivo
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        DOMSource source = new DOMSource(doc);
        
        File archivo = new File(carpetaBase, String.format("%s.xml", solicitud.getNumerosolicitud()));
        StreamResult result = new StreamResult(archivo);
        transformer.transform(source, result);
        
        try {
             
            guardarAuditoria(solicitud.getPk(), tsafeUserDetail.getPk().getUsercode(), 
                    solicitud.getNumerosolicitud(), solicitudTramite.getNumerotramite(), 
                    archivo.getAbsolutePath());

        } catch (Exception e) {
            e.printStackTrace();
            //System.out.println("Error al generar auditoria desde el front>>< "+ e.toString());
        }
        return archivo;
    }
    public String obtenerContenidoArchivo(String archivo) throws FileNotFoundException, IOException { 
        StringBuilder sb = new StringBuilder(); 
	FileReader f = new FileReader(archivo); 
    	String cadena; 
	BufferedReader b = new BufferedReader(f); 
	while((cadena = b.readLine())!=null) { 
		sb.append(cadena.concat("\n"));
	} 
	b.close(); 
        return sb.toString();
   }
    public void crearAuditoria( String csoli,String user, String solicitudNumber, String tramiteNumber,String path) throws Exception{
        TarmInvoiceHistory tih = new TarmInvoiceHistory();
        iv = new InvoiceHistoryController();
        tih.setCsolicitud(csoli);
        tih.setUsercode(user);
        tih.setRegistrationdate(new java.sql.Timestamp(Calendar.getInstance().getTimeInMillis()));
        tih.setSolicitudnumber(solicitudNumber);
        tih.setTramitenumber(tramiteNumber);
        tih.setPathfile(path);
        tih.setContentfile(obtenerContenidoArchivo(path));
        //PersistenceHelper.getEntityManager().persist(tih);
        System.out.println("com.fp.frontend.controller.armas.solicitud.FacturaController.crearAuditoria()<>> va a gualdal" );
        iv.setRecord(tih);
        //iv.update(tih);
        //PersistenceHelper.getEntityManager().crea
        //PersistenceHelper.save(tih);
        iv.save();
        System.out.println("com.fp.frontend.controller.armas.solicitud.FacturaController.crearAuditoria()<>> devio avel gualdado" );

    }
    
    public void generarFacturas(String csolicitud) {
        try {
            TsafeUserDetail tsafeUserDetail = (TsafeUserDetail) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("TSAFEUSERDETAIL");

            String folderPath = ParametersController.find("PATHFACTURASFRONTXML", "1").getTextvalue();
            File carpetaBase = new File(folderPath);
            carpetaBase.mkdirs();
            File arch = sacarFactura(csolicitud, carpetaBase, tsafeUserDetail );
            byte[] fileContent = Files.readAllBytes(Paths.get(arch.getAbsolutePath()));
            this.downloadFile(fileContent, "application/xml", arch.getName());
             
                
                
        } catch (Exception ex) {
            System.out.println("Error al guardar el parametro >>>> " + ex.toString());
            Exceptions.printStackTrace(ex);
        }
    }
    
    
    @Override
    protected void querydatabase() {
        throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody
    }
}
