/*
 * 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.arrebol.taxiservicios.beans.predio;

import com.arrebol.taxiservicios.beans.TaxiGenericBean;
import com.arrebol.taxiservicios.controller.admin.AprobarCancelacionController;
import com.arrebol.taxiservicios.controller.cobranza.CobranzaController;
import com.arrebol.taxiservicios.controller.predio.AbonoLoteController;
import com.arrebol.taxiservicios.controller.predio.LoteController;
import com.arrebol.taxiservicios.controller.predio.PreventaController;
import com.arrebol.taxiservicios.controller.predio.CambiaLoteController;
import com.arrebol.taxiservicios.model.core.Person;
import com.arrebol.taxiservicios.model.enums.EstatusSolicitud;
import com.arrebol.taxiservicios.model.enums.GenericEnumType;
import com.arrebol.taxiservicios.model.enums.PeriodoPago;
import com.arrebol.taxiservicios.model.enums.PersonType;
import com.arrebol.taxiservicios.model.enums.TipoAbono;
import com.arrebol.taxiservicios.model.predio.AbonoLote;
import com.arrebol.taxiservicios.model.predio.Lote;
import com.arrebol.taxiservicios.model.predio.SolicitudTrasferenciaLote;
import com.arrebol.taxiservicios.model.view.PersonListView;
import java.io.Serializable;
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.view.ViewScoped;
import javax.inject.Named;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

/**
 *
 * @author pc one
 */
@Named("cambiarLoteBean")
@ViewScoped
public class cambiarLoteBean extends TaxiGenericBean implements Serializable {

    private static final long serialVersionUID = -7284027390656669184L;
    final Logger logger = LogManager.getLogger(getClass());

    private PreventaController preventaController;
    private CobranzaController cobranzaController;
    private AprobarCancelacionController aprobarCancelacionController;
    private AbonoLoteController abonoLoteController;
    private CambiaLoteController cambiarLoteController;
    private List<AbonoLote> abonosList;
    private Double totalAbonos;
    private LoteController loteController;
    private List<PersonListView> personList;
    private String selectUser;
    private List<Lote> loteListClient;
    private List<Lote> loteListTransfer;
    private String selectedLoteClient;
    private String selectedLoteTransfer;
    private Lote loteTransfer;
    private Boolean active;
    private Boolean validarTrasferencia;
    //solisitud
    private String periodoPago;
    private Integer plazoMeses;
    private Date diaAPagar;
    private Boolean activeInput;
    private Date fechaPagoExtra;
    private Double cantidadPagoExtra;

    @PostConstruct
    public void init() {
        logger.info("init taxiGenericBean");
        try {
            setPreventaController(new PreventaController());
            setPersonList(getPreventaController().findListOfPersonsByType(PersonType.CUSTOMER, getLoggedUser().getLocation()));
        } catch (Exception e) {
            logger.error("taxiGenericBean init", e);
        }
    }

    private Date fechaMasUno(Date fecha) {
        Calendar fechaMasUno = Calendar.getInstance();
        fechaMasUno.setTime(fecha);
        fechaMasUno.add(Calendar.DAY_OF_MONTH, 1);
        return fechaMasUno.getTime();
    }

    public void updateLotes() {
        logger.info("Actualizando lotes");
        setCobranzaController(new CobranzaController());
        setLoteController(new LoteController());
        setLoteListClient(getCobranzaController().fillLoteVendidoByCliente(getSelectUser()));
        setLoteListTransfer(getLoteController().fillAllLotesDisponibles());
    }

    public void prepararTrasferencia() {
        setPeriodoPago("MENSUAL");
        setDiaAPagar(new Date());
        // cargo el lote destino
        setLoteController(new LoteController());
        setLoteTransfer(getLoteController().fillLote(getSelectedLoteTransfer()));
        // Se verifica si existen pagos realizados asociados al lote a cancelar 
        setAprobarCancelacionController(new AprobarCancelacionController());
        List<AbonoLote> abonosL = getAprobarCancelacionController().fillAbonoLoteByLoteAndPagoEstatus(new Lote(getSelectedLoteClient()), GenericEnumType.ENABLED);
        Double totalPago = 0.0;
        if (!abonosL.isEmpty()) {
            // Se extrae el total de los pagos realizados            
            for (AbonoLote abono : abonosL) {
                totalPago = totalPago + abono.getCantidadPagada();
            }
        }
        setTotalAbonos(totalPago);
    }
    
    
    public void resetView() {
        setSelectUser("");
        setSelectedLoteClient("");
        setSelectedLoteTransfer("");
        setPeriodoPago("MENSUAL");
        setPlazoMeses(0);
        setDiaAPagar(new Date());
        setFechaPagoExtra(null);
        setCantidadPagoExtra(null);
    }
    
    public void resetExtras() {
        setFechaPagoExtra(null);
        setCantidadPagoExtra(null);
    }
    
    public void updateByPaymentPeriod() {
        if (getPeriodoPago().equals("QUINCENAL")) {
            setActiveInput(true);
            setDiaAPagar(null);
        } else {
            setActiveInput(false);
        }
    }

    public void resetDetallesTrasferencia() {

    }

    public Boolean verificarPagoExtra(Lote lote, Date fechaI, int numeroPagos, Boolean mensual, Date fechaEx, Double pagoEx, Double anticipoS) {
        //GENERACIÓN DE FECHAS DE PAGO
        //Definición de la fecha de inicio 
        Calendar fechaInicial = Calendar.getInstance();
        fechaInicial.setTime(fechaI);

        //lista de fechas de pago
        List<Calendar> fechasDePago;

        // pago extra
        Date fechaDate = fechaEx;
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(fechaDate);
        int mesPagoExtra = calendar.get(Calendar.MONTH);//int mesDeseado = Calendar.OCTOBER; // Mes deseado: octubre
        int diaPagoExtra = calendar.get(Calendar.DAY_OF_MONTH);//int diaDeseado = 15; // Día deseado: 15                

        // se genera la lista de fechas
        fechasDePago = generarFechasDePagoExtra(fechaInicial, numeroPagos, mensual, mesPagoExtra, diaPagoExtra);

        // Verifico cuantos pagos extra se daran
        int contadorPagosExtra = 0;
        for (Calendar fecha : fechasDePago) {
            int mesFecha = fecha.get(Calendar.MONTH);
            int diaFecha = fecha.get(Calendar.DAY_OF_MONTH);

            if (mesFecha == mesPagoExtra && diaFecha == diaPagoExtra) {
                contadorPagosExtra++;
            }
        }
        // Total a pagar por pagos extra 
        Double totalPagoExtra = pagoEx * contadorPagosExtra;

        // CALCULOS DE TOTALES 
        Double InteresMensualPago = lote.getCosto() * (lote.getManzana().getPredio().getInteresMensual() / 100);
        Double Intereses = InteresMensualPago * numeroPagos;
        Double TotalAPagar = lote.getCosto() + Intereses;
        Double TotalCreadito = TotalAPagar + lote.getManzana().getPredio().getComisionMensual();
        //se extrae los anticipos previos en caso de haber dado alguno durante la reserva 
        setAbonoLoteController(new AbonoLoteController());
        List<AbonoLote> anticiposR = getAbonoLoteController().fillAbonoLoteByLoteAndTipoAbono(lote, TipoAbono.ANTICIPO);
        Double totalAnticipoR = 0.0;
        if (anticiposR != null) {
            for (AbonoLote anticipo : anticiposR) {
                totalAnticipoR = totalAnticipoR + anticipo.getPago();
            }
        }
        // se calcula el anticipo total
        Double totalAnticipo = anticipoS + totalAnticipoR;
        Double TotalCreaditoA = TotalCreadito - totalAnticipo;

        Double diferenciaPagos = TotalCreaditoA - totalPagoExtra;
        Boolean valTotal;
        valTotal = diferenciaPagos > 0;
        System.out.println(diferenciaPagos);
        return valTotal;
    }
    
      public Boolean verificarPagoTotal(Lote lote, int numeroPagos, Double anticipoS) {
        // CALCULOS DE TOTALES 
        Double InteresMensualPago = lote.getCosto() * (lote.getManzana().getPredio().getInteresMensual() / 100);
        Double Intereses = InteresMensualPago * numeroPagos;
        Double TotalAPagar = lote.getCosto() + Intereses;
        Double TotalCreadito = TotalAPagar + lote.getManzana().getPredio().getComisionMensual();
        //se extrae los anticipos previos en caso de haber dado alguno durante la reserva 
        setAbonoLoteController(new AbonoLoteController());
        List<AbonoLote> anticiposR = getAbonoLoteController().fillAbonoLoteByLoteAndTipoAbono(lote, TipoAbono.ANTICIPO);
        Double totalAnticipoR = 0.0;
        if (anticiposR != null) {
            for (AbonoLote anticipo : anticiposR) {
                totalAnticipoR = totalAnticipoR + anticipo.getPago();
            }
        }
        // se calcula el anticipo total
        Double totalAnticipo = anticipoS + totalAnticipoR;
        Double TotalCreaditoA = TotalCreadito - totalAnticipo;
        
        Boolean valTotal;
        valTotal = TotalCreaditoA > 0;
        System.out.println(TotalCreaditoA);
        return valTotal;
    }

    public void guardarSolisitud() {
        try {
            setLoteController(new LoteController());
            setCambiaLoteController(new CambiaLoteController());
            // se busca el lote destino
            Lote loteT = getLoteController().fillLote(getSelectedLoteTransfer());
            // se valida el perido de pago
            Boolean mensual;
            mensual = PeriodoPago.MENSUAL.name().equals(getPeriodoPago());
            //se crea una nueva solicitud de trasferencia
            SolicitudTrasferenciaLote solicitud = new SolicitudTrasferenciaLote();
            solicitud.setId(UUID.randomUUID().toString());
            solicitud.setCliente(new Person(getSelectUser()));
            solicitud.setLoteOrigen(new Lote(getSelectedLoteClient()));
            solicitud.setLoteDestino(new Lote(getSelectedLoteTransfer()));
            solicitud.setEstatusActivo(GenericEnumType.ENABLED);
            solicitud.setEstatusSolicitud(EstatusSolicitud.PENDIENTE);
            solicitud.setAnticipoTrasferencia(getTotalAbonos());
            if (getPeriodoPago().equals("MENSUAL")) {
                solicitud.setPeriodoPago(PeriodoPago.MENSUAL);
            } else if (getPeriodoPago().equals("QUINCENAL")) {
                solicitud.setPeriodoPago(PeriodoPago.QUINCENAL);
            }
            solicitud.setNumeroPagos(getPlazoMeses());
            // le sumo un dia al pago extra para guardarlo
            Date diaAPagarMasUno = fechaMasUno(getDiaAPagar());
            solicitud.setFechaIncioPagos(diaAPagarMasUno);
            
           // se valida que no exista ya una solicitud activas
           List<SolicitudTrasferenciaLote> loteOrigin = getCambiaLoteController().fillSolicitudesTrasferenciaPendienteByLote(getSelectedLoteClient());
            List<SolicitudTrasferenciaLote> loteDestino = getCambiaLoteController().fillSolicitudesTrasferenciaPendienteByLote(getSelectedLoteTransfer());            
            if (!loteOrigin.isEmpty()) {
                showMessage(FacesMessage.SEVERITY_ERROR, "Advertencia", "Ya existen una solicitud de trasferencia para el lote de origen");
            }else if (!loteDestino.isEmpty()){
                showMessage(FacesMessage.SEVERITY_ERROR, "Advertencia", "Ya existen una solicitud de trasferencia para el lote destino");
            } else if(getFechaPagoExtra()!=null && getCantidadPagoExtra()==null ){
                setActive(false);
                showMessage(FacesMessage.SEVERITY_ERROR, "Advertencia", "Defina un monto para el pago extra");
            }else if(getCantidadPagoExtra()!=null && getFechaPagoExtra()==null){
                setActive(false);
                showMessage(FacesMessage.SEVERITY_ERROR, "Advertencia", "Defina una fecha para el pago extra");
            }else if (getFechaPagoExtra() != null && getCantidadPagoExtra() != null && getCantidadPagoExtra() > 0.0) {                               
                 // Convierto la fecha del pago extra a calendar para verificar el dia seleccionado
                Date fechaEx = getFechaPagoExtra();
                Calendar fechaExtra = Calendar.getInstance();
                fechaExtra.setTime(fechaEx);
                fechaExtra.add(Calendar.DATE, 1);
                int diaPagoExtra = fechaExtra.get(Calendar.DAY_OF_MONTH);    
                //Convierto la fecha en el que comenzaran  los abonos para verificar el dia seleccionado
                Date fechaIni = getDiaAPagar();
                Calendar fechaInicio = Calendar.getInstance();
                fechaInicio.setTime(fechaIni);
                fechaInicio.add(Calendar.DATE, 1);
                int diaFechaInicio= fechaInicio.get(Calendar.DAY_OF_MONTH);                    
                 // se insertan los datos del lo pagos extra si lo ahi
                solicitud.setMontoPagoExtra(getCantidadPagoExtra());
                // le sumo un dia a la fecha del pago extra para guardala
                solicitud.setFechaPagosExtra(fechaExtra.getTime());
                // Se valida que el numero del dia seleccionado no sea el mismo que el del pago extra                
                if (diaPagoExtra==diaFechaInicio) {
                    showMessage(FacesMessage.SEVERITY_ERROR, "Advertencia", "El número del día del pago extra no puede ser el mimo que el de los abonos");
                } else if (verificarPagoExtra(loteT, diaAPagarMasUno, getPlazoMeses(), mensual, fechaExtra.getTime(), getCantidadPagoExtra(), getTotalAbonos())) {
                    getCambiaLoteController().addSolcitudTrasferencia(solicitud, getLoggedUser(), true);
                    showMessage(FacesMessage.SEVERITY_INFO, "Solicitado", "La solicitud sé a realizado correctamente");
                    resetView();
                } else {
                    showMessage(FacesMessage.SEVERITY_ERROR, "Advertencia", "El pago extra es demasiado grande Seleccione un monto más pequeño");
                }
            } else {
                if(verificarPagoTotal(loteT, getPlazoMeses(), getTotalAbonos())){
                    getCambiaLoteController().addSolcitudTrasferencia(solicitud, getLoggedUser(), true);
                    showMessage(FacesMessage.SEVERITY_INFO, "Solicitado", "La solicitud sé a realizado correctamente");
                }else{
                    showMessage(FacesMessage.SEVERITY_ERROR, "Error", "El total de los abonos del lote de origen es mayor a costo total del lote destino");
                }
                
            }

        } catch (Exception e) {
            logger.error("taxiGenericBean init", e);
        }
    }

    public List<Calendar> generarFechasDePagoExtra(Calendar fechaInicial, int numeroPagos, Boolean mensual, int mesPagoExtra, int diaPagoExtra) {
        logger.info("Generación fechas con pago extra");
        //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();
        // almacena el estatus del pago extra
        boolean fechaDeseadaAgregada = false;

        int pagosGenerados = 0;
        // se verifica el tipo de pago
        if (mensual) {
            for (int i = 1; i < numeroPagos; i++) {
                // Verifica si el mes actual coincide con el mes deseado
                if (fechaActual.get(Calendar.MONTH) == mesPagoExtra) {
                    // Agrega un registro extra con la fecha específica
                    Calendar fechaExtra = Calendar.getInstance();
                    fechaExtra.set(fechaActual.get(Calendar.YEAR), mesPagoExtra, diaPagoExtra);
                    fechasDePago.add(fechaExtra);
                    fechaDeseadaAgregada = true;
                }

                Calendar fechaSiguiente = (Calendar) fechaActual.clone();
                fechaSiguiente.add(Calendar.MONTH, 1);
                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;
                pagosGenerados++;
            }

        } else {
            for (int i = 0; i < numeroPagos; i++) {
                // Verifica si el mes actual coincide con el mes deseado
                if (fechaActual.get(Calendar.MONTH) == mesPagoExtra) {
                    // Agrega un registro extra con la fecha específica
                    Calendar fechaExtra = Calendar.getInstance();
                    fechaExtra.set(fechaActual.get(Calendar.YEAR), mesPagoExtra, diaPagoExtra);
                    fechasDePago.add(fechaExtra);
                    fechaDeseadaAgregada = true;
                }

                Calendar fechaSiguiente = (Calendar) fechaActual.clone();
                if (fechaSiguiente.get(Calendar.DAY_OF_MONTH) != 15) {
                    if (fechaSiguiente.get(Calendar.DAY_OF_MONTH) < 15) {
                        fechaSiguiente.set(Calendar.DAY_OF_MONTH, 15);
                    } else {
                        fechaSiguiente.add(Calendar.MONTH, 1);
                        fechaSiguiente.set(Calendar.DAY_OF_MONTH, 15);
                    }
                } else {
                    fechaSiguiente.add(Calendar.MONTH, 1);
                    fechaSiguiente.set(Calendar.DAY_OF_MONTH, fechaSiguiente.getActualMaximum(Calendar.DAY_OF_MONTH));
                }
                fechasDePago.add(fechaSiguiente);
                fechaActual = fechaSiguiente;
                pagosGenerados++;
            }
        }

        // Si el número de pagos generado es menor que el número de pagos deseado y aún no se ha agregado la fecha deseada, la agregamos al final
        if (pagosGenerados <= numeroPagos && !fechaDeseadaAgregada) {
            Calendar fechaExtra = Calendar.getInstance();
            fechaExtra.set(fechaActual.get(Calendar.YEAR), mesPagoExtra, diaPagoExtra);
            fechasDePago.add(fechaExtra);
        }

        return fechasDePago;
    }

    public PreventaController getPreventaController() {
        return preventaController;
    }

    public void setPreventaController(PreventaController preventaController) {
        this.preventaController = preventaController;
    }

    public List<PersonListView> getPersonList() {
        return personList;
    }

    public void setPersonList(List<PersonListView> personList) {
        this.personList = personList;
    }

    public String getSelectUser() {
        return selectUser;
    }

    public void setSelectUser(String selectUser) {
        this.selectUser = selectUser;
    }

    public List<Lote> getLoteListClient() {
        return loteListClient;
    }

    public void setLoteListClient(List<Lote> loteListClient) {
        this.loteListClient = loteListClient;
    }

    public List<Lote> getLoteListTransfer() {
        return loteListTransfer;
    }

    public void setLoteListTransfer(List<Lote> loteListTransfer) {
        this.loteListTransfer = loteListTransfer;
    }

    public String getSelectedLoteClient() {
        return selectedLoteClient;
    }

    public void setSelectedLoteClient(String selectedLoteClient) {
        this.selectedLoteClient = selectedLoteClient;
    }

    public String getSelectedLoteTransfer() {
        return selectedLoteTransfer;
    }

    public void setSelectedLoteTransfer(String selectedLoteTransfer) {
        this.selectedLoteTransfer = selectedLoteTransfer;
    }

    public LoteController getLoteController() {
        return loteController;
    }

    public void setLoteController(LoteController loteController) {
        this.loteController = loteController;
    }

    public CobranzaController getCobranzaController() {
        return cobranzaController;
    }

    public void setCobranzaController(CobranzaController cobranzaController) {
        this.cobranzaController = cobranzaController;
    }

    public AprobarCancelacionController getAprobarCancelacionController() {
        return aprobarCancelacionController;
    }

    public void setAprobarCancelacionController(AprobarCancelacionController aprobarCancelacionController) {
        this.aprobarCancelacionController = aprobarCancelacionController;
    }

    public List<AbonoLote> getAbonosList() {
        return abonosList;
    }

    public void setAbonosList(List<AbonoLote> abonosList) {
        this.abonosList = abonosList;
    }

    public Double getTotalAbonos() {
        return totalAbonos;
    }

    public void setTotalAbonos(Double totalAbonos) {
        this.totalAbonos = totalAbonos;
    }

    public String getPeriodoPago() {
        return periodoPago;
    }

    public void setPeriodoPago(String periodoPago) {
        this.periodoPago = periodoPago;
    }

    public Integer getPlazoMeses() {
        return plazoMeses;
    }

    public void setPlazoMeses(Integer plazoMeses) {
        this.plazoMeses = plazoMeses;
    }

    public Date getDiaAPagar() {
        return diaAPagar;
    }

    public void setDiaAPagar(Date diaAPagar) {
        this.diaAPagar = diaAPagar;
    }

    public Boolean getActiveInput() {
        return activeInput;
    }

    public void setActiveInput(Boolean activeInput) {
        this.activeInput = activeInput;
    }

    public Boolean getActive() {
        return active;
    }

    public void setActive(Boolean active) {
        this.active = active;
    }

    public Date getFechaPagoExtra() {
        return fechaPagoExtra;
    }

    public void setFechaPagoExtra(Date fechaPagoExtra) {
        this.fechaPagoExtra = fechaPagoExtra;
    }

    public Double getCantidadPagoExtra() {
        return cantidadPagoExtra;
    }

    public void setCantidadPagoExtra(Double cantidadPagoExtra) {
        this.cantidadPagoExtra = cantidadPagoExtra;
    }

    public AbonoLoteController getAbonoLoteController() {
        return abonoLoteController;
    }

    public void setAbonoLoteController(AbonoLoteController abonoLoteController) {
        this.abonoLoteController = abonoLoteController;
    }

    public CambiaLoteController getCambiaLoteController() {
        return cambiarLoteController;
    }

    public void setCambiaLoteController(CambiaLoteController cambiarLoteController) {
        this.cambiarLoteController = cambiarLoteController;
    }

    public Lote getLoteTransfer() {
        return loteTransfer;
    }

    public void setLoteTransfer(Lote loteTransfer) {
        this.loteTransfer = loteTransfer;
    }

    public Boolean getValidarTrasferencia() {
        return validarTrasferencia;
    }

    public void setValidarTrasferencia(Boolean validarTrasferencia) {
        this.validarTrasferencia = validarTrasferencia;
    }

}
