/*
 * Arrebol Consultancy copyright.
 *
 * This code belongs to Arrebol Consultancy
 * its use, redistribution or modification are prohibited
 * without written authorization from Arrebol Consultancy.
 */
package com.crov.prase.prase;

import com.arrebol.taxiservicios.beans.Datatable;
import com.arrebol.taxiservicios.beans.TaxiGenericBean;
import com.arrebol.taxiservicios.controller.admin.CustomerController;
import com.arrebol.taxiservicios.controller.admin.DriverController;
import com.arrebol.taxiservicios.controller.admin.EmployeeController;
import com.arrebol.taxiservicios.controller.admin.GenericPersonController;
import com.arrebol.taxiservicios.controller.admin.GenericValidationController;
import com.arrebol.taxiservicios.controller.admin.TaxiController;
import com.arrebol.taxiservicios.model.admin.Taxi;
import com.arrebol.taxiservicios.model.catalog.Color;
import com.arrebol.taxiservicios.model.catalog.Vehicle;
import com.arrebol.taxiservicios.model.core.Address;
import com.arrebol.taxiservicios.model.core.ContactNumber;
import com.arrebol.taxiservicios.model.core.Person;
import com.arrebol.taxiservicios.model.enums.AddressType;
import com.arrebol.taxiservicios.model.enums.BasicType;
import com.arrebol.taxiservicios.model.enums.EstatusSolicitud;
import com.arrebol.taxiservicios.model.enums.GenericEnumType;
import com.arrebol.taxiservicios.model.enums.MetodoPago;
import com.arrebol.taxiservicios.model.enums.PersonType;
import com.arrebol.taxiservicios.model.enums.PhoneType;
import com.arrebol.taxiservicios.model.enums.PolizaEstatus;
import com.arrebol.taxiservicios.model.enums.TipoAbono;
import com.crov.prase.controller.catalog.TipoPolizaController;
import com.crov.prase.controller.prase.PagosPolizaController;
import com.crov.prase.controller.prase.PolizaController;
import com.crov.prase.model.catalog.Hospitales;
import com.crov.prase.model.catalog.TipoPoliza;
import com.crov.prase.model.prase.DetellePagoPoliza;
import com.crov.prase.model.prase.PagosPoliza;
import com.crov.prase.model.prase.Poliza;
import com.crov.prase.model.prase.SolicitudCancelacionPoliza;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.view.ViewScoped;
import javax.inject.Named;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.primefaces.event.ReorderEvent;
import org.primefaces.event.RowEditEvent;

/**
 *
 * @author Oscar Vargas
 */
@Named("polizaBean")
@ViewScoped
public class PolizaBean extends TaxiGenericBean implements Serializable, Datatable {

   public void newPoliza() {
      logger.info("Nueva póliza");
      setEditPoliza(false);
      setPolizaAdd(new Poliza());
      getPolizaAdd().setCantidadPagada(0.0);
      getPolizaAdd().setPeriodoGracia(7);
      setInitDate(new Date());
      setPrimerPago(0.0);
      setContador(0);
   }

   @Override
   public void addRow() {
      logger.info("Agregando póliza");
      try {
         Taxi taxiTmp = null;

         if (idTaxi != null && !idTaxi.isEmpty()) {
            taxiTmp = getTaxiController().getTaxiByIdReport2(idTaxi);
         } else {
            FacesMessage msg = new FacesMessage("Vehículo vacio", "Se debe de seleccionar un vehículo");
            FacesContext.getCurrentInstance().addMessage(null, msg);
            return;
         }

         getPolizaAdd().setId(UUID.randomUUID().toString());
         getPolizaAdd().setActive(true);
         getPolizaAdd().setCreatedOn(correcciónDeHr(new Date(), -7));
         getPolizaAdd().setInitDate(correcciónDeDias(getInitDate(), 1));
         getPolizaAdd().setTaxi(taxiTmp);
         getPolizaAdd().setCustomer(taxiTmp.getCustomer());
         getPolizaAdd().setTipoPoliza(new TipoPoliza(idTipoPoliza));
         getPolizaAdd().setAsesor(new Person(idAsesor));
         getPolizaAdd().setCreatedBy(getLoggedUser());
         getPolizaAdd().setLocation(getLoggedUser().getLocation());
         getPolizaAdd().setUMA(getUMA());
         // Validación del periodo de pago para la generación de folios
         switch (getIdPeriocidad()) {
            case "ANUAL":
               getPolizaAdd().setFolio(obtenerFolio("PA", getPolizaAdd().getInitDate()));
               break;
            case "SEMESTRAL":
               getPolizaAdd().setFolio(obtenerFolio("PS", getPolizaAdd().getInitDate()));
               break;
            case "TRIMESTRAL":
               getPolizaAdd().setFolio(obtenerFolio("PT", getPolizaAdd().getInitDate()));
               break;
            case "MENSUAL":
               getPolizaAdd().setFolio(obtenerFolio("PM", getPolizaAdd().getInitDate()));
               break;
            default:
               break;
         }

         if (isLiquidado()) {
            getPolizaAdd().setEstatus(PolizaEstatus.LIQUIDADO);
            getPolizaAdd().setCantidadPagada(getPolizaAdd().getAmount());
         } else {
            getPolizaAdd().setEstatus(PolizaEstatus.PENDIENTE);
         }

         Calendar calendar = Calendar.getInstance();
         calendar.setTime(getPolizaAdd().getInitDate());
         calendar.add(Calendar.YEAR, 1);
         getPolizaAdd().setEndDate(calendar.getTime());

         controller.save(getPolizaAdd());

         if (!isLiquidado()) {
            Calendar fechaInicial = Calendar.getInstance();
            fechaInicial.setTime(getPolizaAdd().getInitDate());

            int numeroPagos = 0;

            switch (getIdPeriocidad()) {
               case "ANUAL":
                  numeroPagos = 1;
                  break;
               case "SEMESTRAL":
                  numeroPagos = 2;
                  break;
               case "TRIMESTRAL":
                  numeroPagos = 4;
                  break;
               case "MENSUAL":
                  numeroPagos = 12;
                  break;
               default:
                  break;
            }

            List<Calendar> fechasPago = generarFechasDePago(fechaInicial, numeroPagos, getPolizaAdd().getPeriodoGracia());
            setContador(1);
            for (Calendar fecha : fechasPago) {
               if (getContador() == 1) {
                  PagosPoliza pagoPoliza = new PagosPoliza();
                  pagoPoliza.setCantidadPagada(0D);
                  pagoPoliza.setPoliza(getPolizaAdd());
                  pagoPoliza.setCreatedBy(getLoggedUser());
                  pagoPoliza.setCreatedOn(correcciónDeHr(new Date(), -7));
                  pagoPoliza.setDiferenciaPago(0D);
                  pagoPoliza.setPago(getPrimerPago());
                  pagoPoliza.setEstatusActivo(GenericEnumType.ENABLED);
                  pagoPoliza.setPagoEstatus(GenericEnumType.DISABLED);
                  pagoPoliza.setTipoPago(TipoAbono.ABONO);
                  pagoPoliza.setFechaAPagar(fecha.getTime());
                  getController().save(pagoPoliza);
                  setContador(2);
               } else {
                  PagosPoliza pagoPoliza = new PagosPoliza();
                  pagoPoliza.setCantidadPagada(0D);
                  pagoPoliza.setPoliza(getPolizaAdd());
                  pagoPoliza.setCreatedBy(getLoggedUser());
                  pagoPoliza.setCreatedOn(correcciónDeHr(new Date(), -7));
                  pagoPoliza.setDiferenciaPago(0D);
                  pagoPoliza.setPago(((getPolizaAdd().getAmount() - getPolizaAdd().getCantidadPagada()) - getPrimerPago()) / (numeroPagos - 1));
                  pagoPoliza.setEstatusActivo(GenericEnumType.ENABLED);
                  pagoPoliza.setPagoEstatus(GenericEnumType.DISABLED);
                  pagoPoliza.setTipoPago(TipoAbono.ABONO);
                  pagoPoliza.setFechaAPagar(fecha.getTime());
                  getController().save(pagoPoliza);
               }
            }
         } else {
            PagosPoliza pagoPoliza = new PagosPoliza();
            pagoPoliza.setId(UUID.randomUUID().toString());
            pagoPoliza.setPoliza(getPolizaAdd());
            pagoPoliza.setEstatusActivo(GenericEnumType.ENABLED);
            pagoPoliza.setTipoPago(TipoAbono.ABONO);
            pagoPoliza.setPagoEstatus(GenericEnumType.ENABLED);
            pagoPoliza.setFechaAPagar(correcciónDeHr(new Date(), -7));
            pagoPoliza.setPago(getPolizaAdd().getAmount());
            pagoPoliza.setCantidadPagada(getPolizaAdd().getAmount());
            pagoPoliza.setDiferenciaPago(0D);
            pagoPoliza.setCreatedBy(getLoggedUser());
            pagoPoliza.setCreatedOn(correcciónDeHr(new Date(), -7));
            getController().save(pagoPoliza);

            DetellePagoPoliza detalle = new DetellePagoPoliza();
            detalle.setId(UUID.randomUUID().toString());
            detalle.setPagoPoliza(pagoPoliza);
            detalle.setEstatusActivo(GenericEnumType.ENABLED);
            detalle.setEstatusPago(GenericEnumType.ENABLED);
            detalle.setTipoPago(TipoAbono.ABONO);
            detalle.setFechaPago(correcciónDeHr(new Date(), -7));
            detalle.setCantidadPagada(pagoPoliza.getCantidadPagada());
            detalle.setCobro(getLoggedUser());
            detalle.setFolio(obtenerFolioAbonos("A-PRASE"));
            detalle.setMetodoPago(MetodoPago.valueOf(getMetodoPago()));
            detalle.setCreatedBy(getLoggedUser());
            detalle.setCreatedOn(correcciónDeHr(new Date(), -7));
            getController().save(detalle);
         }

         setPoliza(getController().findActive(getLoggedUser().getLocation()));
         clearPolizaForm();
         FacesMessage msg = new FacesMessage("Nueva póliza", "Se agregó correctamente");
         FacesContext.getCurrentInstance().addMessage(null, msg);
      } catch (Exception e) {
         showMessage(FacesMessage.SEVERITY_ERROR, "Error", "Ocurrió un error al guardar la póliza.");
         logger.error("addRow(): " + e);
      }
   }

   public void clearPolizaForm() {
      logger.info("Limpiando formulario póliza ");
      setPolizaAdd(null);
      setIdTaxi(null);
      setIdTipoPoliza(null);
      setIdAsesor(null);
      setIdPeriocidad(null);
      setUMA(null);
   }

   public void cargarPoliza() {
      logger.info("cargarPoliza()");
      setEditPoliza(true);
      try {
         setPolizaAdd(getSelectedPoliza());
         setInitDate(getSelectedPoliza().getInitDate());
         setIdTaxi(getSelectedPoliza().getTaxi().getId());
         setIdTipoPoliza(getSelectedPoliza().getTipoPoliza().getId());
         setIdAsesor(getSelectedPoliza().getAsesor().getId());
         setIdPeriocidad("NO");
         setUMA(getSelectedPoliza().getUMA());
      } catch (Exception e) {
         logger.error("cargarPoliza(): " + e);
      }
   }

   public void cargarPagos() {
      logger.info("cargarPagos()");
      try {
         setPagosPolizaList(getPagosPolizaController().fillPagosPedientesPolizaByPoliza(getSelectedPoliza()));
      } catch (Exception e) {
         logger.error("cargarPagos(): " + e);
      }
   }

   public void actualizarPagoPoliza() {
      logger.info("actualizarPagoPoliza()");
      try {
         getPagosPolizaController().updatePago(getSelectedPago(), getLoggedUser());
         getPolizaList();
         cargarPagos();
         showMessage(FacesMessage.SEVERITY_INFO, "Pago actualizado", "Se actualizó la nueva fecha de pago");
      } catch (Exception e) {
         showMessage(FacesMessage.SEVERITY_ERROR, "Error", "Ocurrió un error al actualizar el pago");
         logger.error("actualizarPagoPoliza(): " + e);
      }
   }

   public void cargarDevolucion() {
      setComentario("");
      setMontoRenbolso(getSelectedPoliza().getCantidadPagada());
   }

   public void editarPoliza() {
      logger.info("editarPoliza()");
      try {
         Taxi taxiTmp = null;
         if (getIdTaxi() != null && !getIdTaxi().isEmpty()) {
            taxiTmp = getTaxiController().getTaxiByIdReport2(getIdTaxi());
         } else {
            FacesMessage msg = new FacesMessage("Vehículo vacio", "Se debe de seleccionar un vehículo");
            FacesContext.getCurrentInstance().addMessage(null, msg);
            return;
         }
         getPolizaAdd().setTaxi(taxiTmp);
         getPolizaAdd().setInitDate(correcciónDeDias(getInitDate(), 1));
         getPolizaAdd().setCustomer(taxiTmp.getCustomer());
         getPolizaAdd().setTipoPoliza(new TipoPoliza(getIdTipoPoliza()));
         getPolizaAdd().setAsesor(new Person(getIdAsesor()));
         getPolizaAdd().setUMA(getUMA());
         getPolizaAdd().setLastUpdatedOn(correcciónDeHr(new Date(), -7));
         getPolizaAdd().setLastUpdatedBy(getLoggedUser());
         getController().update(getPolizaAdd());
         setPoliza(getController().findActive(getLoggedUser().getLocation()));
         clearPolizaForm();
         showMessage(FacesMessage.SEVERITY_INFO, "Actualización realizada", "Póliza actualizada correctamente.");
         logger.info("Póliza actualizada correctamente");
      } catch (Exception e) {
         showMessage(FacesMessage.SEVERITY_ERROR, "Error", "Ocurrió un error al tratar de actualizar la póliza.");
         logger.error("editarPoliza(): " + e);
      }
   }

   public void editarPolizaModoPago() {
      logger.info("editarPolizaModoPago()");
      try {
         if (getIdPeriocidad().equals("0")) {
            showMessage(FacesMessage.SEVERITY_WARN, "Error", "La periodicidad es obligatoria");
            return;
         }
         if (getSelectedPoliza().getAmount() < getSelectedPoliza().getCantidadPagada()) {
            showMessage(FacesMessage.SEVERITY_WARN, "Error", "El nuevo monto no puede ser menor que la cantidad que ya se ha pagado");
            return;
         }
         // se  define la fecha de inicio
         getSelectedPoliza().setInitDate(correcciónDeDias(getInitDate(), 1));
         Calendar fechaInicial = Calendar.getInstance();
         fechaInicial.setTime(getSelectedPoliza().getInitDate());
         // se determina le numero de pagos que se realizaran
         int numeroPagos = 0;
         switch (getIdPeriocidad()) {
            case "ANUAL":
               numeroPagos = 1;
               break;
            case "SEMESTRAL":
               numeroPagos = 2;
               break;
            case "TRIMESTRAL":
               numeroPagos = 4;
               break;
            case "MENSUAL":
               numeroPagos = 12;
               break;
            default:
               break;
         }
         List<DetellePagoPoliza> detallesPagosRealizados = getPagosPolizaController().fillDetellePagoPolizaPagadosByPoliza(getSelectedPoliza());
         List<PagosPoliza> pagos = getPagosPolizaController().fillPagosPolizaByPoliza(getSelectedPoliza());
         // se generan las fechas de pago
         List<Calendar> fechasPago = generarFechasDePago(fechaInicial, numeroPagos, 0);
         if (getPagosPolizaController().editarPolizaModoPago(getSelectedPoliza(), numeroPagos, fechasPago, detallesPagosRealizados, pagos, getLoggedUser())) {
            clearPolizaForm();
            getPolizaList();
            showMessage(FacesMessage.SEVERITY_INFO, "Actualización realizada", "Póliza actualizada correctamente.");
            logger.info("Póliza actualizada correctamente");
         } else {
            showMessage(FacesMessage.SEVERITY_ERROR, "ERROR", "Ocurrió un error al tratar de actualizar la póliza.");
            logger.info("Ocurrió un error al tratar de actualizar la póliza");
         }
      } catch (Exception e) {
         showMessage(FacesMessage.SEVERITY_FATAL, "ERROR", "Ocurrió un error al tratar de actualizar la póliza.");
         logger.error("editarPolizaModoPago(): " + e);
      }
   }

   public List<Calendar> generarFechasDePago(Calendar fechaInicial, int numeroPagos, int periodoGracia) {
      logger.info("Generación fechas");
      //lista de fechas
      List<Calendar> fechasDePago = new ArrayList<>();

      fechasDePago.add(fechaInicial);

      Calendar fechaActual = (Calendar) fechaInicial.clone();
      //captura el dia de una fecha en caso de que no se encuntre en le mes siguinte
      boolean detenerFecha = false;
      Calendar fechaDetenida = Calendar.getInstance();

      for (int i = 1; i < numeroPagos; i++) {
         Calendar fechaSiguiente = (Calendar) fechaActual.clone();

         switch (numeroPagos) {
            case 2: {
               fechaSiguiente.add(Calendar.MONTH, 6);
               break;
            }
            case 4: {
               fechaSiguiente.add(Calendar.MONTH, 3);
               break;
            }
            case 12: {
               fechaSiguiente.add(Calendar.MONTH, 1);
               break;
            }

         }

         if (detenerFecha == false) {
            if (fechaActual.get(Calendar.DAY_OF_MONTH) > fechaSiguiente.getActualMaximum(Calendar.DAY_OF_MONTH)) {
               detenerFecha = true;
               fechaDetenida = (Calendar) fechaActual.clone();
               fechaSiguiente.set(Calendar.DAY_OF_MONTH, fechaSiguiente.getActualMaximum(Calendar.DAY_OF_MONTH));
            }
         } else {
            if (fechaSiguiente.get(Calendar.DAY_OF_MONTH) <= fechaDetenida.get(Calendar.DAY_OF_MONTH)) {
               detenerFecha = false;
               fechaSiguiente.set(Calendar.DAY_OF_MONTH, fechaDetenida.get(Calendar.DAY_OF_MONTH));
            } else {
               fechaSiguiente.set(Calendar.DAY_OF_MONTH, fechaSiguiente.getActualMaximum(Calendar.DAY_OF_MONTH));
            }
         }
         fechasDePago.add(fechaSiguiente);
         fechaActual = fechaSiguiente;
      }

      // Se valida si hubo un periodo de gracia para agregárselo a la primera fecha de pago
      if (periodoGracia > 0) {
         fechasDePago.get(0).add(Calendar.DATE, periodoGracia);
      }

      return fechasDePago;
   }

   public void liquidadoChange() {
      if (isLiquidado()) {
         getPolizaAdd().setPeriodoGracia(0);
      }
   }

   @Override
   public void deleteRow() {
      logger.info("deleteRow");
      try {
         controller.delete(selectedPoliza.getId(), getLoggedUser(), getComentario());
         getPolizaList();
         selectedPoliza = null;
         showMessage(FacesMessage.SEVERITY_INFO, "Póliza deshabilitado", "Se deshabilito correctamente.");
      } catch (Exception e) {
         logger.error("deleteRow: " + e);
         showMessage(FacesMessage.SEVERITY_FATAL, "Póliza", "Ocurrió un error");
      }
   }

   public void solicitarCacelacionPoliza() {
      logger.info("solicitarCacelacionPoliza()");
      if (getMontoRenbolso().isNaN() || getMontoRenbolso() < 0.0 || getMontoRenbolso() > getSelectedPoliza().getCantidadPagada()) {
         showMessage(FacesMessage.SEVERITY_WARN, "Error", "Debe de colocar un monto mayor a 0 y menor al monto abotonado hasta el momento: $" + getSelectedPoliza().getCantidadPagada());
         return;
      }
      List<SolicitudCancelacionPoliza> verificarPolizas = getController().findSolicitudCancelacionPolizaByPolizaAndEstatus(getSelectedPoliza(), EstatusSolicitud.PENDIENTE);
      if (!verificarPolizas.isEmpty()) {
         showMessage(FacesMessage.SEVERITY_WARN, "Error", "Ya hay una solicitud de cancelación de póliza en proceso");
         return;
      }
      try {
         SolicitudCancelacionPoliza socitud = new SolicitudCancelacionPoliza();
         socitud.setEstatusActivo(GenericEnumType.ENABLED);
         socitud.setLocation(getLoggedUser().getLocation());
         socitud.setPoliza(getSelectedPoliza());
         socitud.setSolicitante(getLoggedUser());
         socitud.setFechaPago(null);
         socitud.setEstatusSolicitud(EstatusSolicitud.PENDIENTE);
         socitud.setMontoDevolucion(getMontoRenbolso());
         socitud.setComentario(getComentario());
         if (getController().saveSolicitudCancelacionPoliza(socitud, getLoggedUser())) {
            showMessage(FacesMessage.SEVERITY_INFO, "Solicitud realizada", "Solicitud de cancelación de poliza realizada correctamente");
         } else {
            showMessage(FacesMessage.SEVERITY_ERROR, "Error", "Error al generar la solicitud de cancelación de poliza");
         }
      } catch (Exception e) {
         logger.error("solicitarCacelacionPoliza(): " + e);
         showMessage(FacesMessage.SEVERITY_FATAL, "Error", "Error al generar la solicitud de cancelación de piliza");
      }
   }

   private String obtenerFolio(String ab, Date fecha) {
      logger.info("Obteniendo último folio ");
      try {
         // Se cargan los abonos para validar el folio
         String abreviacion = ab;
         Poliza ultimoFolio = getController().fillFoliosByPolizas2(abreviacion);
         // Se valida si ya existen folios registrados para el proyecto y se le asigna el último encontrado
         int consecutivo = 0;
         if (ultimoFolio != null) {
            String folior = ultimoFolio.getFolio();
            // Dividir el folio en partes utilizando el guion como separador
            String[] partes = folior.split("-");
            // Obtener la parte del consecutivo
            String consecutivoParte = partes[4];
            // Convertir el consecutivo a un entero
            consecutivo = Integer.parseInt(consecutivoParte);
         }
         // se formatea el consecutivo
         String numeroFormateado = String.format("%05d", consecutivo + 1);
         String folio;
         // se formatea la fecha
         SimpleDateFormat formatoF = new SimpleDateFormat("dd-MM-yy");
         String fechaFormateada = formatoF.format(fecha);
         // Se valida si se creara el primer folio
         if (consecutivo == 0) {
            folio = abreviacion + "-" + fechaFormateada + "-" + "00001";
         } else {
            folio = abreviacion + "-" + fechaFormateada + "-" + numeroFormateado;
         }
         return folio;
      } catch (NumberFormatException e) {
         logger.error("Ocurrió un erro al obtener el último folio ");
         showMessage(FacesMessage.SEVERITY_ERROR, "Error", "Ocurrió un error al generar el folio");
         return null;
      }
   }

   private String obtenerFolioAbonos(String ab) {
      logger.info("Obteniendo último folio ");
      try {
         // Se cargan los abonos para validar el folio
         String abreviacion = ab;
         DetellePagoPoliza ultimoFolio = getPagosPolizaController().fillFoliosByPagos(abreviacion);
         // Se valida si ya existen folios registrados para el proyecto y se le asigna el último encontrado
         int consecutivo = 0;
         if (ultimoFolio != null) {
            String folior = ultimoFolio.getFolio();
            // Dividir el folio en partes utilizando el guion como separador
            String[] partes = folior.split("-");
            // Obtener la parte del consecutivo
            String consecutivoParte = partes[2];
            // Convertir el consecutivo a un entero
            consecutivo = Integer.parseInt(consecutivoParte);
         }
         // se formatea el consecutivo
         String numeroFormateado = String.format("%06d", consecutivo + 1);
         String folio;
         // Se obtiene el año actual
         Calendar calendario = Calendar.getInstance();
         int ano = calendario.get(Calendar.YEAR);
         String anoActual = String.valueOf(ano);
         // Se valida si se creara el primer folio
         if (consecutivo == 0) {
            folio = abreviacion + "-" + "000001" + "-" + anoActual;
         } else {
            folio = abreviacion + "-" + numeroFormateado + "-" + anoActual;
         }
         return folio;
      } catch (NumberFormatException e) {
         logger.error("Ocurrió un erro al obtener el último folio ");
         showMessage(FacesMessage.SEVERITY_ERROR, "Error", "Ocurrió un error al generar el folio");
         return null;
      }
   }

   private Date correcciónDeHr(Date fecha, int horas) {
      Calendar calendar = Calendar.getInstance();
      calendar.setTime(fecha);
      calendar.add(Calendar.HOUR_OF_DAY, horas);
      Date nuevaFecha = calendar.getTime();
      return nuevaFecha;
   }

   @Override
   public void editRow(RowEditEvent event) {

   }

   @Override
   public void onRowCancel(RowEditEvent event) {
      showMessage(FacesMessage.SEVERITY_INFO, "Edición Cancelada", ((Hospitales) event.getObject()).getName());
   }

   @Override
   public void onRowReorder(ReorderEvent event) {
      showMessage(FacesMessage.SEVERITY_INFO, "Registro Movido", "De columna: " + (event.getFromIndex() + 1) + " a columna: " + (event.getToIndex() + 1));
   }

   @PostConstruct
   public void init() {
      logger.info("init");
      try {
         loadBundlePropertyFile();
         setPrimerPago(0.0);

         setController(new PolizaController());
         setTaxiController(new TaxiController());
         setTipoPolizaController(new TipoPolizaController());
         setEmployeeController(new EmployeeController());
         setCustomerController(new CustomerController());
         setGenericController(new GenericValidationController());
         setPagosPolizaController(new PagosPolizaController());
         setDriverController(new DriverController());
         setGenericPersonController(new GenericPersonController() {
         });

         setEditPoliza(false);
         setTipoPoliza(getTipoPolizaController().findTipoPoliza());
         setTaxi(getTaxiController().findAllTaxisByLocation(getLoggedUser().getLocation()));
         setAsesor(getEmployeeController().getAllPersonsByPersonTye(PersonType.EMPLOYEE));
         setListCustomer(getGenericPersonController().getAllPersonsByPersonTye(PersonType.CUSTOMER));
         getPolizaList(); //obtiene las polizas activas y desactivadas

         setPolizaAdd(new Poliza());
         getPolizaAdd().setPeriodoGracia(7);
         setInitDate(new Date());

         setListVehicle(getTaxiController().findAllVehicles());
         setListColor(getTaxiController().fillColorsComboBox());
         setListDriver(getTaxiController().getAllPersonsByPersonTye(PersonType.DRIVER));

         //Se cargan los números telefónicos de los clientes en las pólizas
         for (Poliza pol : getPoliza()) {
            try {
               List<ContactNumber> tels = getCustomerController().fillPreferencedContactNumberByPerson(pol.getCustomer().getId());
               for (ContactNumber tel : tels) {
                  if (tel.getPreferenced() != null && tel.getPreferenced().equals(true)) {
                     pol.setTelefonoCliente(tel.getPhone());
                  }
               }
            } catch (Exception e) {
               logger.error(pol.getId() + " :" + e);
            }
         }

      } catch (Exception e) {
         logger.error(e);
      }
   }

   public void agregarCliente() {
      logger.info("Agregando nuevo cliente");
      try {
         Person per = addCustomer();
         if (per.getId() != null) {
            showMessage(FacesMessage.SEVERITY_INFO, "Cliente agregado", "El cliente se agregó correctamente");
            if (getSerialNumber() != null && !getSerialNumber().isEmpty()) {
               if (addVehicle(per)) {
                  showMessage(FacesMessage.SEVERITY_INFO, "Vehículo agregado", "Vehículo agregado correctamente");
               } else {
                  showMessage(FacesMessage.SEVERITY_ERROR, "Error al agregar el vehículo", "Ocurrió un error al agregar el vehículo");
               }
            } else {
               logger.info("No se agregó ningún vehículo");
            }
         } else {
            showMessage(FacesMessage.SEVERITY_ERROR, "Error al agregar el cliente", "Ocurrió un error al agregar el cliente");
         }
         clearFormClient();
         setTaxi(getTaxiController().findAllTaxisByLocation(getLoggedUser().getLocation()));
      } catch (Exception e) {
         showMessage(FacesMessage.SEVERITY_FATAL, "ERROR", "Ocurrió un error al agregar el cliente");
         logger.error("agregarCliente " + e);
      }
   }

   private boolean addVehicle(Person customer) {
      logger.info("addVehicle");
      try {
         Taxi tax = new Taxi();
         tax.setLocation(getLoggedUser().getLocation());
         tax.setActive(true);
         tax.setPlaca(getPlaca());
         tax.setEconomicNumber("");
         tax.setSerialNumber(getSerialNumber());
         tax.setMotorNmumber(getMotorNumber());
         tax.setYear(getYear());
         tax.setCustomer(customer);
         Person con = null;
         tax.setDriver(con);
         tax.setVehicle(new Vehicle(getSelectVehicle()));
         tax.setGps(BasicType.DISABLED);
         tax.setApc(BasicType.DISABLED);
         tax.setComments("");
         boolean success = getCustomerController().addVehiculo(tax, getLoggedUser());
         if (success) {
            logger.info("Taxi agregado correctamente");
            return success;
         } else {
            logger.error("Ocurrió un error al agregar el taxi");
            return success;
         }
      } catch (Exception e) {
         logger.error("addVehicle(): " + e);
         return false;
      }
   }

   private Person addCustomer() {
      logger.info("addCustomer");
      try {
         Person person = new Person();
         person.setId(UUID.randomUUID().toString());

         person.setFirstName(getPrimerNombre());
         person.setSecondName(getSegundoNombre());
         person.setLastName(getPrimerApellido());
         person.setMiddleName(getSegundoApellido());

         person.setActive(true);
         person.setRoot(false);
         person.setCreatedOn(new Date());
         person.setPersonType(PersonType.CUSTOMER);
         person.setLocation(getLoggedUser().getLocation());
         person.setAjustador(Boolean.FALSE);
         boolean success = getCustomerController().addPerson(person, getLoggedUser().getUserName(), true);

         if (success) {

            if (getTelefono() != null && !getTelefono().isEmpty()) {
               logger.info("Agregando número telefónico ");
               ContactNumber num = new ContactNumber();
               num.setPhone(getTelefono());
               num.setPhoneType(PhoneType.MOBILE);
               num.setPreferenced(true);
               num.setPerson(person);
               getDriverController().addContactNumber(num, getLoggedUser(), true);
            }

            if (getStreet() != null && !getStreet().isEmpty()) {
               Address direccion = new Address();
               direccion.setStreet(getStreet());
               direccion.setExtendedAddress(getExtendedAddress());
               direccion.setLocality(getLocality());
               direccion.setRegion(getRegion());
               direccion.setZipCode(getZipCode());
               direccion.setPerson(person);
               direccion.setAddressType(AddressType.HOME);
               getDriverController().addAddress(direccion, getLoggedUser(), true);
            }

            logger.info("Cliente agregado correctamente");
            return person;
         } else {
            logger.error("Ocurrió un error al agregar el cliente");
            return new Person();
         }
      } catch (Exception e) {
         logger.error("addCustomer: " + e);
         return new Person();
      }
   }

   public void prueva() {
      logger.info("Hola");
   }

   public void clearFormClient() {
      setPrimerNombre(null);
      setSegundoNombre(null);
      setPrimerApellido(null);
      setSegundoApellido(null);
      setRfc(null);
      setSelectColor(null);
      setSelectDriver(null);
      setSelectVehicle(null);
      setPlaca(null);
      setEconomicNumber(null);
      setSerialNumber(null);
      setMotorNumber(null);
      setYear(null);
   }

   public void resetagregarVehiculoForm() {
      setIdCustomer(null);
      setSerialNumber(null);
      setPlaca(null);
      setYear(null);
      setMotorNumber(null);
      setSelectVehicle(null);
   }

   public void agregarVehiculo() {
      logger.info("agregarVehiculo()");
      try {
         if (addVehicle(new Person(getIdCustomer()))) {
            setTaxi(getTaxiController().findAllTaxisByLocation(getLoggedUser().getLocation()));
            showMessage(FacesMessage.SEVERITY_INFO, "Vehículo agregado", "Vehículo agregado correctamente");
         } else {
            showMessage(FacesMessage.SEVERITY_ERROR, "Error al agregar el vehículo", "Ocurrió un error al agregar el vehículo");
         }
      } catch (Exception e) {
         showMessage(FacesMessage.SEVERITY_FATAL, "Error al agregar el vehículo", "Ocurrió un error al agregar el vehículo");
         logger.error("agregarVehiculo(): " + e);
      }
   }

   private Date correcciónDeDias(Date fecha, int dias) {
      Calendar calendar = Calendar.getInstance();
      calendar.setTime(fecha);
      calendar.add(Calendar.DAY_OF_YEAR, dias);
      return calendar.getTime();
   }

   /*
    public void soapInit() {
        try {
            // URL del servicio SOAP
            URL url = new URL("http://www.libroazul.com/ws/wslibroazul.asmx");
            // Abrir conexión HTTP
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            // Configurar la conexión HTTP
            connection.setRequestMethod("POST");
            connection.setRequestProperty("Content-Type", "text/xml; charset=utf-8");
            connection.setRequestProperty("SOAPAction", "\"http://www.libroazul.com/ws/IniciarSesion\"");
            connection.setDoOutput(true);
            // Construir el cuerpo del mensaje SOAP
            String xmlInput = "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ws=\"http://www.libroazul.com/ws/\">\n"
                    + "    <soap:Body>\n"
                    + "        <ws:IniciarSesion>\n"
                    + "            <Usuario>user</Usuario>\n"
                    + "            <Contrasena>123</Contrasena>\n"
                    + "        </ws:IniciarSesion>\n"
                    + "    </soap:Body>\n"
                    + "</soap:Envelope>";
            // Enviar la solicitud SOAP
            try ( OutputStream outputStream = connection.getOutputStream()) {
                byte[] input = xmlInput.getBytes("utf-8");
                outputStream.write(input, 0, input.length);
            }
            // Obtener la respuesta del servicio
            BufferedReader reader;
            StringBuilder response = new StringBuilder();
            String line;
            try {
                reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                while ((line = reader.readLine()) != null) {
                    response.append(line);
                }
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            // Mostrar la respuesta del servicio
            logger.info("Respuesta del servicio: " + response.toString());
            // Cerrar la conexión HTTP
            connection.disconnect();
        } catch (IOException e) {
            logger.error("Error al realizar la petición SOAP: " + e.getMessage());
        }
    }
    */
   private PolizaController controller;
   private TaxiController taxiController;
   private TipoPolizaController tipoPolizaController;
   private GenericValidationController genericController;
   private EmployeeController employeeController;
   private CustomerController customerController;
   private PagosPolizaController pagosPolizaController;
   private DriverController driverController;
   private GenericPersonController genericPersonController;

   private List<Poliza> poliza;
   private List<Poliza> polizasActivasList;
   private List<Poliza> polizasEmitidasList;
   private List<Poliza> polizasPedientesDePagoList;
   private List<Poliza> polizasVencidasList;
   private List<Poliza> polizasFinalizadasList;
   private List<Poliza> polizasCaseladasList;
   private List<PagosPoliza> pagosPolizaList;
   private PagosPoliza selectedPago;
   private List<Taxi> taxi;
   private List<TipoPoliza> tipoPoliza;
   private List<Person> asesor;
   private List<Person> listCustomer;
   private String idTaxi;
   private String idTipoPoliza;
   private String idAsesor;
   private String idPeriocidad;
   private String UMA;
   private Boolean editPoliza;
   private Date initDate;
   private String metodoPago;
   private Double primerPago;

   private Poliza selectedPoliza;
   private Poliza polizaAdd;

   //CUSTOMER
   private String primerNombre;
   private String segundoNombre;
   private String primerApellido;
   private String segundoApellido;
   private String rfc;
   private String telefono;

   private String street;
   private String extendedAddress;
   private String locality;
   private String region;
   private String zipCode;

   //TAXI
   private List<Color> listColor;
   private String selectColor;
   private List<Vehicle> listVehicle;
   private String selectVehicle;
   private List<Person> listDriver;
   private String selectDriver;
   private String placa;
   private String economicNumber;
   private String serialNumber;
   private String motorNumber;
   private String year;
   private boolean liquidado;
   private int contador;

   private String idCustomer;

   private String comentario;
   private Double montoRenbolso;

   public int getContador() {
      return contador;
   }

   public void setContador(int contador) {
      this.contador = contador;
   }

   public String getComentario() {
      return comentario;
   }

   public void setComentario(String comentario) {
      this.comentario = comentario;
   }

   public String getIdPeriocidad() {
      return idPeriocidad;
   }

   public Double getPrimerPago() {
      return primerPago;
   }

   public void setPrimerPago(Double primerPago) {
      this.primerPago = primerPago;
   }

   public void setIdPeriocidad(String idPeriocidad) {
      this.idPeriocidad = idPeriocidad;
   }

   public EmployeeController getEmployeeController() {
      return employeeController;
   }

   public void setEmployeeController(EmployeeController employeeController) {
      this.employeeController = employeeController;
   }

   public List<Person> getAsesor() {
      return asesor;
   }

   public void setAsesor(List<Person> asesor) {
      this.asesor = asesor;
   }

   public String getIdAsesor() {
      return idAsesor;
   }

   public void setIdAsesor(String idAsesor) {
      this.idAsesor = idAsesor;
   }

   public String getIdTaxi() {
      return idTaxi;
   }

   public void setIdTaxi(String idTaxi) {
      this.idTaxi = idTaxi;
   }

   public String getIdTipoPoliza() {
      return idTipoPoliza;
   }

   public void setIdTipoPoliza(String idTipoPoliza) {
      this.idTipoPoliza = idTipoPoliza;
   }

   public TipoPolizaController getTipoPolizaController() {
      return tipoPolizaController;
   }

   public void setTipoPolizaController(TipoPolizaController tipoPolizaController) {
      this.tipoPolizaController = tipoPolizaController;
   }

   public List<TipoPoliza> getTipoPoliza() {
      return tipoPoliza;
   }

   public void setTipoPoliza(List<TipoPoliza> tipoPoliza) {
      this.tipoPoliza = tipoPoliza;
   }

   public List<Taxi> getTaxi() {
      return taxi;
   }

   public void setTaxi(List<Taxi> taxi) {
      this.taxi = taxi;
   }

   public TaxiController getTaxiController() {
      return taxiController;
   }

   public void setTaxiController(TaxiController taxiController) {
      this.taxiController = taxiController;
   }

   public GenericValidationController getGenericController() {
      return genericController;
   }

   public void setGenericController(GenericValidationController genericController) {
      this.genericController = genericController;
   }

   public PolizaController getController() {
      return controller;
   }

   public void setController(PolizaController controller) {
      this.controller = controller;
   }

   public List<Poliza> getPoliza() {
      return poliza;
   }

   public void setPoliza(List<Poliza> poliza) {
      this.poliza = poliza;
   }

   public Poliza getSelectedPoliza() {
      return selectedPoliza;
   }

   public void setSelectedPoliza(Poliza selectedPoliza) {
      this.selectedPoliza = selectedPoliza;
   }

   public Poliza getPolizaAdd() {
      return polizaAdd;
   }

   public void setPolizaAdd(Poliza polizaAdd) {
      this.polizaAdd = polizaAdd;
   }

   public CustomerController getCustomerController() {
      return customerController;
   }

   public void setCustomerController(CustomerController customerController) {
      this.customerController = customerController;
   }

   public List<Color> getListColor() {
      return listColor;
   }

   public void setListColor(List<Color> listColor) {
      this.listColor = listColor;
   }

   public String getSelectColor() {
      return selectColor;
   }

   public void setSelectColor(String selectColor) {
      this.selectColor = selectColor;
   }

   public List<Vehicle> getListVehicle() {
      return listVehicle;
   }

   public void setListVehicle(List<Vehicle> listVehicle) {
      this.listVehicle = listVehicle;
   }

   public String getSelectVehicle() {
      return selectVehicle;
   }

   public void setSelectVehicle(String selectVehicle) {
      this.selectVehicle = selectVehicle;
   }

   public List<Person> getListDriver() {
      return listDriver;
   }

   public void setListDriver(List<Person> listDriver) {
      this.listDriver = listDriver;
   }

   public String getSelectDriver() {
      return selectDriver;
   }

   public void setSelectDriver(String selectDriver) {
      this.selectDriver = selectDriver;
   }

   public String getPrimerNombre() {
      return primerNombre;
   }

   public void setPrimerNombre(String primerNombre) {
      this.primerNombre = primerNombre;
   }

   public String getSegundoNombre() {
      return segundoNombre;
   }

   public void setSegundoNombre(String segundoNombre) {
      this.segundoNombre = segundoNombre;
   }

   public String getPrimerApellido() {
      return primerApellido;
   }

   public void setPrimerApellido(String primerApellido) {
      this.primerApellido = primerApellido;
   }

   public String getSegundoApellido() {
      return segundoApellido;
   }

   public void setSegundoApellido(String segundoApellido) {
      this.segundoApellido = segundoApellido;
   }

   public String getPlaca() {
      return placa;
   }

   public void setPlaca(String placa) {
      this.placa = placa;
   }

   public String getEconomicNumber() {
      return economicNumber;
   }

   public void setEconomicNumber(String economicNumber) {
      this.economicNumber = economicNumber;
   }

   public String getSerialNumber() {
      return serialNumber;
   }

   public void setSerialNumber(String serialNumber) {
      this.serialNumber = serialNumber;
   }

   public String getMotorNumber() {
      return motorNumber;
   }

   public void setMotorNumber(String motorNumber) {
      this.motorNumber = motorNumber;
   }

   public String getYear() {
      return year;
   }

   public void setYear(String year) {
      this.year = year;
   }

   public boolean isLiquidado() {
      return liquidado;
   }

   public void setLiquidado(boolean liquidado) {
      this.liquidado = liquidado;
   }

   public PagosPolizaController getPagosPolizaController() {
      return pagosPolizaController;
   }

   public void setPagosPolizaController(PagosPolizaController pagosPolizaController) {
      this.pagosPolizaController = pagosPolizaController;
   }

   public String getRfc() {
      return rfc;
   }

   public void setRfc(String rfc) {
      this.rfc = rfc;
   }

   public DriverController getDriverController() {
      return driverController;
   }

   public void setDriverController(DriverController driverController) {
      this.driverController = driverController;
   }

   public String getTelefono() {
      return telefono;
   }

   public void setTelefono(String telefono) {
      this.telefono = telefono;
   }

   public String getStreet() {
      return street;
   }

   public void setStreet(String street) {
      this.street = street;
   }

   public String getExtendedAddress() {
      return extendedAddress;
   }

   public void setExtendedAddress(String extendedAddress) {
      this.extendedAddress = extendedAddress;
   }

   public String getLocality() {
      return locality;
   }

   public void setLocality(String locality) {
      this.locality = locality;
   }

   public String getRegion() {
      return region;
   }

   public void setRegion(String region) {
      this.region = region;
   }

   public String getZipCode() {
      return zipCode;
   }

   public void setZipCode(String zipCode) {
      this.zipCode = zipCode;
   }

   public String getUMA() {
      return UMA;
   }

   public void setUMA(String UMA) {
      this.UMA = UMA;
   }

   public Boolean getEditPoliza() {
      return editPoliza;
   }

   public void setEditPoliza(Boolean editPoliza) {
      this.editPoliza = editPoliza;
   }

   public Date getInitDate() {
      return initDate;
   }

   public void setInitDate(Date initDate) {
      this.initDate = initDate;
   }

   public String getIdCustomer() {
      return idCustomer;
   }

   public void setIdCustomer(String idCustomer) {
      this.idCustomer = idCustomer;
   }

   public List<Person> getListCustomer() {
      return listCustomer;
   }

   public void setListCustomer(List<Person> listCustomer) {
      this.listCustomer = listCustomer;
   }

   public GenericPersonController getGenericPersonController() {
      return genericPersonController;
   }

   public void setGenericPersonController(GenericPersonController genericPersonController) {
      this.genericPersonController = genericPersonController;
   }

   public String getMetodoPago() {
      return metodoPago;
   }

   public void setMetodoPago(String metodoPago) {
      this.metodoPago = metodoPago;
   }

   public Double getMontoRenbolso() {
      return montoRenbolso;
   }

   public void setMontoRenbolso(Double montoRenbolso) {
      this.montoRenbolso = montoRenbolso;
   }

   public List<Poliza> getPolizasActivasList() {
      return polizasActivasList;
   }

   public void setPolizasActivasList(List<Poliza> polizasActivasList) {
      this.polizasActivasList = polizasActivasList;
   }

   public List<Poliza> getPolizasEmitidasList() {
      return polizasEmitidasList;
   }

   public void setPolizasEmitidasList(List<Poliza> polizasEmitidasList) {
      this.polizasEmitidasList = polizasEmitidasList;
   }

   public List<Poliza> getPolizasPedientesDePagoList() {
      return polizasPedientesDePagoList;
   }

   public void setPolizasPedientesDePagoList(List<Poliza> polizasPedientesDePagoList) {
      this.polizasPedientesDePagoList = polizasPedientesDePagoList;
   }

   public List<Poliza> getPolizasVencidasList() {
      return polizasVencidasList;
   }

   public void setPolizasVencidasList(List<Poliza> polizasVencidasList) {
      this.polizasVencidasList = polizasVencidasList;
   }

   public List<Poliza> getPolizasCaseladasList() {
      return polizasCaseladasList;
   }

   public void setPolizasCaseladasList(List<Poliza> polizasCaseladasList) {
      this.polizasCaseladasList = polizasCaseladasList;
   }

   public List<Poliza> getPolizasFinalizadasList() {
      return polizasFinalizadasList;
   }

   public void setPolizasFinalizadasList(List<Poliza> polizasFinalizadasList) {
      this.polizasFinalizadasList = polizasFinalizadasList;
   }

   public List<PagosPoliza> getPagosPolizaList() {
      return pagosPolizaList;
   }

   public void setPagosPolizaList(List<PagosPoliza> pagosPolizaList) {
      this.pagosPolizaList = pagosPolizaList;
   }

   public PagosPoliza getSelectedPago() {
      return selectedPago;
   }

   public void setSelectedPago(PagosPoliza selectedPago) {
      this.selectedPago = selectedPago;
   }

   public void getPolizaList() {
      try {
         setPoliza(getController().getAllPolizasByLocation(getLoggedUser().getLocation()));
         setPolizasActivasList(new ArrayList<>());
         setPolizasEmitidasList(new ArrayList<>());
         setPolizasPedientesDePagoList(new ArrayList<>());
         setPolizasVencidasList(new ArrayList<>());
         setPolizasFinalizadasList(new ArrayList<>());
         setPolizasCaseladasList(new ArrayList<>());
         Date fechaActual = new Date();
         int NoPolizasConErrorDeCargado = 0;
         for (Poliza selecPoliza : getPoliza()) {
            switch (selecPoliza.getEstatus()) {
               case CANCELADO:
                  getPolizasCaseladasList().add(selecPoliza);
                  break;
               case LIQUIDADO:
                  if (selecPoliza.getEndDate().after(fechaActual)) {
                     getPolizasActivasList().add(selecPoliza);
                  } else {
                     getPolizasFinalizadasList().add(selecPoliza);
                  }
                  break;
               default:
                  PagosPoliza proximoPago = getPagosPolizaController().getSiguintePagosPolizaARealizarByPoliza(selecPoliza);
                  if (proximoPago == null) {
                     NoPolizasConErrorDeCargado++;
                     continue;
                  }
                  if (proximoPago.getNuevaFechaAPagar() != null) {
                     getPolizasPedientesDePagoList().add(selecPoliza);
                  } else if (proximoPago.getFechaAPagar().before(fechaActual)) {
                     getPolizasVencidasList().add(selecPoliza);
                  } else {
                     getPolizasEmitidasList().add(selecPoliza);
                  }
                  break;
            }
         }
         if (NoPolizasConErrorDeCargado > 0) {
            showMessage(FacesMessage.SEVERITY_WARN, "ADVERTENCIA", NoPolizasConErrorDeCargado + " pólizas no se pudieron cargar correctamente ");
         }
      } catch (Exception e) {
         showMessage(FacesMessage.SEVERITY_FATAL, "ERROR", "OCURRIÓ UN ERROR AL TRATA DE CARGAR LAS PÓLIZAS");
         logger.error("getPolizaList(): " + e);
      }
   }

   public String validarColores(Boolean estatus) {
      // Validadar color 
      if (estatus) {
         return "";
      } else {
         return "grayRow";
      }
   }

   public void resetSelectedComentario() {
      setComentario(null);
   }

   private static final long serialVersionUID = -136031528440947006L;
   final Logger logger = LogManager.getLogger(PolizaBean.class);
}
