/*
 * 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.crov.prase.prase;

import com.arrebol.taxiservicios.beans.TaxiGenericBean;
import com.arrebol.taxiservicios.controller.admin.GenericValidationController;
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.PolizaEstatus;
import com.arrebol.taxiservicios.model.enums.TipoAbono;
import com.arrebol.taxiservicios.model.enums.TipoTarjeta;
import com.crov.prase.controller.prase.PagosPolizaController;
import com.crov.prase.controller.prase.PolizaController;
import com.crov.prase.model.prase.DetellePagoPoliza;
import com.crov.prase.model.prase.HistorialAbonoMultiple;
import com.crov.prase.model.prase.PagosPoliza;
import com.crov.prase.model.prase.Poliza;
import com.crov.prase.model.prase.SolicitudDevolucionDetellePagoPoliza;
import java.io.Serializable;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.view.ViewScoped;
import javax.inject.Named;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

/**
 *
 * @author Crov
 */
@Named("pagosPolizasBean")
@ViewScoped
public class PagosPolizasBean extends TaxiGenericBean implements Serializable {

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

   private PolizaController polizaController;
   private PagosPolizaController pagosPolizaController;
   private GenericValidationController genericController;

   private List<Poliza> poliza;
   private Poliza selectedPoliza;
   private List<PagosPoliza> listPagosPolizas;
   private PagosPoliza selectedPago;
   private List<DetellePagoPoliza> listDetallePagosPolizas;
   private DetellePagoPoliza selectedDetellePago;
   private String pagoSiguiente;
   private Double cantidadAPagar;
   private String comentario;
   private Boolean pagoExitoso;
   private String imagen;
   private String metodoPago;
   private String tipoTargeta;
   private HistorialAbonoMultiple selectedHistorialAbonoMultiple;

   private String comentarioDevolucionPago;
   private String detallePagoDisponibleParaDevocion;

   @PostConstruct
   public void init() {
      logger.info("init");
      try {
         loadBundlePropertyFile();
         setPolizaController(new PolizaController());
         setPagosPolizaController(new PagosPolizaController());
         setGenericController(new GenericValidationController());
         cargarPolizas();
      } catch (Exception e) {
         logger.error(e);
      }
   }

   public void cargarPolizas() {
      logger.info("cargarPolizas()");
      setPoliza(getPolizaController().findActive(getLoggedUser().getLocation()));
   }

   public void cargarPagosPoliza() {
      logger.info("cargarPagosPoliza()");
      try {
         // se caga la lista de pagos
         setListPagosPolizas(getPagosPolizaController().fillPagosPolizaByPoliza(getSelectedPoliza()));
         // se encuentra el siguiente pago a realizar
         String idSiguinetePago = "";
         for (PagosPoliza pa : getListPagosPolizas()) {
            if (pa.getPagoEstatus().equals(GenericEnumType.DISABLED) || pa.getPagoEstatus().equals(GenericEnumType.INCOMPLETE)) {
               idSiguinetePago = pa.getId();
               break;
            }
         }
         setPagoSiguiente(idSiguinetePago);
      } catch (Exception e) {
         logger.error("cargarPagosPoliza(): " + e);
      }
   }

   public void cargarPago() {
      setCantidadAPagar(getSelectedPago().getDiferenciaPago());
      setSelectedDetellePago(null);
      setMetodoPago("");
      setTipoTargeta("0");
   }

   public void limpiarTipoPago() {
      setTipoTargeta("0");
   }

   public void pagarMultiple() {
      logger.info("pagarMultiple()");
      setPagoExitoso(false);

      if (getGenericController().existClosingDayByCreatedOn(new Date(), getLoggedUser())) {
         showMessage(FacesMessage.SEVERITY_WARN, "Error", "No se puede hacer ninguna acción si existe un corte del día");
         return;
      }

      if (getGenericController().existStableGeneralBoxByCurdate(getLoggedUser())) {
         showMessage(FacesMessage.SEVERITY_WARN, "Dia cerrado", "No se puede hacer ninguna acción porque ya existe un cuadre de caja chica del día");
         return;
      }

      if (getCantidadAPagar() <= 0.0) {
         showMessage(FacesMessage.SEVERITY_WARN, "Error", "El monto a pagar debe de ser mayor a 0");
         return;
      }

      // se actuliza el pago
      String estatusPagoMultiple = getPagosPolizaController().procesarPagoMultiple(getSelectedPoliza(), getCantidadAPagar(), getMetodoPago(), getComentario(), getLoggedUser());
      if (esUUIDValido(estatusPagoMultiple)) {
         setImagen("images/prase_logo.jpeg");
         setSelectedHistorialAbonoMultiple(getPagosPolizaController().getHistorialAbonoMultipleById(estatusPagoMultiple));
         setPagoExitoso(true);
         cargarPolizas();
         showMessage(FacesMessage.SEVERITY_INFO, "Pago realizado", "El pago multiple se a realizado correctamente");
      } else {
         setPagoExitoso(false);
         setSelectedHistorialAbonoMultiple(null);
         showMessage(FacesMessage.SEVERITY_ERROR, "Error", estatusPagoMultiple);
      }
   }

   public void pagar() {
      logger.info("pagar()");
      setPagoExitoso(false);

      if (getGenericController().existClosingDayByCreatedOn(new Date(), getLoggedUser())) {
         showMessage(FacesMessage.SEVERITY_WARN, "Error", "No se puede hacer ninguna acción si existe un corte del día");
         return;
      }

      if (getGenericController().existStableGeneralBoxByCurdate(getLoggedUser())) {
         showMessage(FacesMessage.SEVERITY_WARN, "Dia cerrado", "No se puede hacer ninguna acción porque ya existe un cuadre de caja chica del día");
         return;
      }

      if (getCantidadAPagar() > (getSelectedPago().getPago() - getSelectedPago().getCantidadPagada())) {
         showMessage(FacesMessage.SEVERITY_WARN, "ERROR", "La cantidad a pagar no puede ser mayor al pago restante del abono");
         return;
      }

      if (getMetodoPago().equals("TARJETA") && getTipoTargeta().equals("0")) {
         showMessage(FacesMessage.SEVERITY_WARN, "ERROR", "Si selecciono el método de pago con TARJETA, debe de seleccionar el TIPO DE TARJETA ");
         return;
      }

      // se valida el pago realizado sea el siguiente según el consecutivo
      if (getSelectedPago().getId().equals(getPagoSiguiente())) {
         // se actuliza el pago
         if (actualizarAbono(getSelectedPago(), getCantidadAPagar(), getMetodoPago())) {
            // se actualiza la lista de pagos y polizas
            setPagoExitoso(true);
            // se carga el ultimo detalle para el tiked
            setSelectedDetellePago(getPagosPolizaController().getUltimoDetalleByPago(getSelectedPago().getId()));
            cargarPagosPoliza();
            cargarDetalles();
            cargarPolizas();
            showMessage(FacesMessage.SEVERITY_INFO, "Pago realizado", "El pago se realizó correctamente");
         } else {
            showMessage(FacesMessage.SEVERITY_ERROR, "Error", "Ocurrió un error al realizar el pago");
         }
      } else {
         showMessage(FacesMessage.SEVERITY_WARN, "Error", "Solo puede pagar el pago consecutivo");
      }
   }

   private boolean actualizarAbono(PagosPoliza pagoA, Double montoPagado, String metodoDePago) {
      try {
         setImagen("images/prase_logo.jpeg");
         // se optiene el folio consecutivo
         String folio = obtenerFolio("A-PRASE");
         if (folio != null) {
            // se genera el detalle pago
            DetellePagoPoliza detalle = new DetellePagoPoliza();
            detalle.setPagoPoliza(pagoA);
            detalle.setEstatusActivo(GenericEnumType.ENABLED);
            detalle.setEstatusPago(GenericEnumType.ENABLED);
            detalle.setTipoPago(TipoAbono.ABONO);
            detalle.setFechaPago(correcciónDeHr(new Date(), -7));
            detalle.setCantidadPagada(montoPagado);
            detalle.setCobro(getLoggedUser());
            detalle.setFolio(folio);
            detalle.setMetodoPago(MetodoPago.valueOf(metodoDePago));
            detalle.setTipoTarjeta(detalle.getMetodoPago().equals(MetodoPago.TARJETA) ? TipoTarjeta.valueOf(getTipoTargeta()) : null);
            getPagosPolizaController().createDetellePago(detalle, getLoggedUser());

            // se actualisa el pago pricipal
            pagoA.setCantidadPagada(pagoA.getCantidadPagada() + detalle.getCantidadPagada());
            pagoA.setDiferenciaPago(pagoA.getPago() - pagoA.getCantidadPagada());
            if (Math.abs(pagoA.getDiferenciaPago()) < 0.01) {
               pagoA.setPagoEstatus(GenericEnumType.ENABLED);
               pagoA.setCantidadPagada(pagoA.getPago());
               pagoA.setDiferenciaPago(0.0);
            } else {
               pagoA.setPagoEstatus(GenericEnumType.INCOMPLETE);
            }
            getPagosPolizaController().updatePago(pagoA, getLoggedUser());

            // se actuliza la venta
            pagoA.getPoliza().setCantidadPagada(pagoA.getPoliza().getCantidadPagada() + detalle.getCantidadPagada());
            pagoA.getPoliza().setLastUpdatedBy(getLoggedUser());
            pagoA.getPoliza().setLastUpdatedOn(new Date());
            //se valida si la venta ya fue liquidada
            double cantidadPa = pagoA.getPoliza().getCantidadPagada();
            double costoTotal = pagoA.getPoliza().getAmount();
            if (Math.abs(cantidadPa - costoTotal) < 0.10) {
               pagoA.getPoliza().setEstatus(PolizaEstatus.LIQUIDADO);
               pagoA.getPoliza().setCantidadPagada(pagoA.getPoliza().getAmount());
            }
            getPolizaController().update(pagoA.getPoliza());

            logger.info("El pago se realizó correctamente");
            return true;
         } else {
            logger.error("Ocurrió un error al generar el folio");
            return false;
         }
      } catch (Exception e) {
         logger.error("actualizarAbono(): " + e);
         return false;
      }
   }

   public void solicitarDevolusionDePago() {
      logger.info("solicitarDevolusionDePago()");
      try {
         List<SolicitudDevolucionDetellePagoPoliza> solisitudesPendientes = getPagosPolizaController().fillSolicitudesPedientesByDetallePago(getSelectedDetellePago().getId());
         if (!solisitudesPendientes.isEmpty()) {
            showMessage(FacesMessage.SEVERITY_WARN, "Error", "Este detalle ya tiene una solicitud de devolución de pago en proceso");
            return;
         }
         SolicitudDevolucionDetellePagoPoliza solicitud = new SolicitudDevolucionDetellePagoPoliza();
         solicitud.setEstatusActivo(GenericEnumType.ENABLED);
         solicitud.setLocation(getLoggedUser().getLocation());
         solicitud.setDetallePagoSolicitud(getSelectedDetellePago());
         solicitud.setDetallePagoDevolucion(null);
         solicitud.setUsuarioSolicito(getLoggedUser());
         solicitud.setUsuarioCorte(getLoggedUser());
         solicitud.setEstatusSolicitud(EstatusSolicitud.PENDIENTE);
         solicitud.setMontoDevolucion(getSelectedDetellePago().getCantidadPagada());
         solicitud.setComentario(getComentarioDevolucionPago());
         getPagosPolizaController().createSolicitudDevolucionDetellePagoPoliza(solicitud, getLoggedUser());
         showMessage(FacesMessage.SEVERITY_INFO, "Solicitud realizada", "Solicitud de devolución de abono realizada correctamente");
      } catch (Exception e) {
         logger.error("solicitarDevolusionDePago(): " + e);
         showMessage(FacesMessage.SEVERITY_ERROR, "Error", "Error al generar la solicitud de devolución de pago");
      }
   }

   public void limpiarFormDevolusionDetallePago() {
      setComentario("");
   }

   public void limpiarDetallePago() {
      setSelectedDetellePago(null);
      setPagoExitoso(false);
      setCantidadAPagar(0.0);
      setMetodoPago("");
   }

   public void limpiarDetallePagoMultiple() {
      setSelectedHistorialAbonoMultiple(null);
      setPagoExitoso(false);
      setCantidadAPagar(0.0);
      setMetodoPago("");
      setComentario(null);
   }

   private String obtenerFolio(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;
      }
   }

   public void cargarDetalles() {
      try {
         List<DetellePagoPoliza> listaDeDetallesPago = getPagosPolizaController().fillDetellePagoPolizaByPago(getSelectedPago().getId());
         setListDetallePagosPolizas(listaDeDetallesPago);
         // se encuentra el siguiente pago que se puede devolver
         String idDetallePago = "";
         Collections.reverse(listaDeDetallesPago);
         for (DetellePagoPoliza pa : listaDeDetallesPago) {
            if (pa.getEstatusPago().equals(GenericEnumType.ENABLED) && pa.getTipoPago().equals(TipoAbono.ABONO)) {
               idDetallePago = pa.getId();
               break;
            }
         }
         setDetallePagoDisponibleParaDevocion(idDetallePago);
      } catch (Exception e) {
         logger.error("cargarDetalles(): " + e);
         showMessage(FacesMessage.SEVERITY_ERROR, "Error", "Ocurrió un error al tratar de cargar los detalles de pago");
      }
   }

   public void reimprimirTicket() {
      setPagoExitoso(true);
      try {
         setImagen("images/prase_logo.jpeg");
      } catch (Exception e) {
         logger.error("Error al definir el logo para el tiked  " + e);
      }
   }

   public static boolean esUUIDValido(String valor) {
      if (valor == null) {
         return false;
      }
      try {
         UUID uuid = UUID.fromString(valor);
         return valor.equals(uuid.toString());
      } catch (IllegalArgumentException ex) {
         return false;
      }
   }

   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;
   }

   public String validarColores(String estatus) {
      // Validadar color 
      if (estatus.equals("LIQUIDADO")) {
         return "bgVerde";
      } else {
         return "";
      }
   }

   public PolizaController getPolizaController() {
      return polizaController;
   }

   public void setPolizaController(PolizaController polizaController) {
      this.polizaController = polizaController;
   }

   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 List<PagosPoliza> getListPagosPolizas() {
      return listPagosPolizas;
   }

   public void setListPagosPolizas(List<PagosPoliza> listPagosPolizas) {
      this.listPagosPolizas = listPagosPolizas;
   }

   public PagosPoliza getSelectedPago() {
      return selectedPago;
   }

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

   public PagosPolizaController getPagosPolizaController() {
      return pagosPolizaController;
   }

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

   public String getPagoSiguiente() {
      return pagoSiguiente;
   }

   public void setPagoSiguiente(String pagoSiguiente) {
      this.pagoSiguiente = pagoSiguiente;
   }

   public Double getCantidadAPagar() {
      return cantidadAPagar;
   }

   public void setCantidadAPagar(Double cantidadAPagar) {
      this.cantidadAPagar = cantidadAPagar;
   }

   public GenericValidationController getGenericController() {
      return genericController;
   }

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

   public Boolean getPagoExitoso() {
      return pagoExitoso;
   }

   public void setPagoExitoso(Boolean pagoExitoso) {
      this.pagoExitoso = pagoExitoso;
   }

   public String getImagen() {
      return imagen;
   }

   public void setImagen(String imagen) {
      this.imagen = imagen;
   }

   public String getMetodoPago() {
      return metodoPago;
   }

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

   public DetellePagoPoliza getSelectedDetellePago() {
      return selectedDetellePago;
   }

   public void setSelectedDetellePago(DetellePagoPoliza selectedDetellePago) {
      this.selectedDetellePago = selectedDetellePago;
   }

   public List<DetellePagoPoliza> getListDetallePagosPolizas() {
      return listDetallePagosPolizas;
   }

   public void setListDetallePagosPolizas(List<DetellePagoPoliza> listDetallePagosPolizas) {
      this.listDetallePagosPolizas = listDetallePagosPolizas;
   }

   public String getComentario() {
      return comentario;
   }

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

   public HistorialAbonoMultiple getSelectedHistorialAbonoMultiple() {
      return selectedHistorialAbonoMultiple;
   }

   public void setSelectedHistorialAbonoMultiple(HistorialAbonoMultiple selectedHistorialAbonoMultiple) {
      this.selectedHistorialAbonoMultiple = selectedHistorialAbonoMultiple;
   }

   public String getComentarioDevolucionPago() {
      return comentarioDevolucionPago;
   }

   public void setComentarioDevolucionPago(String comentarioDevolucionPago) {
      this.comentarioDevolucionPago = comentarioDevolucionPago;
   }

   public String getDetallePagoDisponibleParaDevocion() {
      return detallePagoDisponibleParaDevocion;
   }

   public void setDetallePagoDisponibleParaDevocion(String detallePagoDisponibleParaDevocion) {
      this.detallePagoDisponibleParaDevocion = detallePagoDisponibleParaDevocion;
   }

   public String getTipoTargeta() {
      return tipoTargeta;
   }

   public void setTipoTargeta(String tipoTargeta) {
      this.tipoTargeta = tipoTargeta;
   }

}
