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

import com.arrebol.taxiservicios.beans.Datatable;
import com.arrebol.taxiservicios.beans.TaxiGenericBean;
import com.arrebol.taxiservicios.controller.admin.BitacoraController;
import com.arrebol.taxiservicios.controller.admin.ClosingDayController;
import com.arrebol.taxiservicios.controller.admin.GenericValidationController;
import com.arrebol.taxiservicios.controller.admin.StableSmallBoxController;
import com.arrebol.taxiservicios.controller.admin.TransferMoneyLocationController;
import com.arrebol.taxiservicios.model.admin.ClosingDay;
import com.arrebol.taxiservicios.model.admin.Expense;
import com.arrebol.taxiservicios.model.admin.FinancingCustomer;
import com.arrebol.taxiservicios.model.admin.StableSmallBox;
import com.arrebol.taxiservicios.model.admin.TransferMoneyLocation;
import com.arrebol.taxiservicios.model.catalog.Location;
import com.arrebol.taxiservicios.model.enums.BasicType;
import com.arrebol.taxiservicios.model.stocktaking.Invoice;
import com.arrebol.taxiservicios.model.view.report.PaymentClient;
import java.io.Serializable;
import java.math.BigDecimal;
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;
import org.primefaces.PrimeFaces;
import org.primefaces.event.ReorderEvent;
import org.primefaces.event.RowEditEvent;

/**
 *
 * @author Carlos Janitzio Zavala Lopez <janitzio.zavala@arrebol.com.mx>
 */
@Named("transferMoneyLocationBean")
@ViewScoped
public class TransferMoneyLocationBean extends TaxiGenericBean implements Serializable, Datatable {

    /**
     * Update stable small box list between start date and end date.
     */
    public void updateList() {
        logger.info("updateList");
        try {
            if (getStartDate().after(getEndDate())) {
                showMessage(FacesMessage.SEVERITY_ERROR,
                        "Transferencia de dinero entre sucursales",
                        getBundlePropertyFile().getString("start.date.after.error"));
            } else {
                setUpDates(false);
                setTransfer(
                        getController().findTransferMoneyLocationBetweenDates(
                                getStartDate(),
                                getEndDate(),
                                getLoggedUser().getLocation().getId()
                        )
                );
            }
        } catch (Exception e) {
            logger.error("updateList", e);
        }
    }

    @Override
    public void editRow(RowEditEvent event) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void onRowCancel(RowEditEvent event) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void onRowReorder(ReorderEvent event) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }
    
    public void autorizarPendingExpense() {
        logger.info("noPrintSale");

        try {
            boolean success = getController().autorizarExpense(getSelectedExpenseAuth().getId(),getLoggedUser());

            if (success) {
                setSelectedExpenseAuth(null);

                showMessage(FacesMessage.SEVERITY_INFO,
                        "Autorizar",
                        "Se autorizó correctamente");
               setExpenseAuth(getController().getExpenseNoPaidPending(getLoggedUser().getLocation().getId()));
            } else {
                logger.error("Sale " + getSelectedExpenseAuth() + "was not changed to no print");
                showMessage(FacesMessage.SEVERITY_ERROR,
                        "Autorizar",
                        "No se pudo autorizar");
            }

        } catch (Exception e) {
            logger.error("autorizar: " + e);

            showMessage(FacesMessage.SEVERITY_FATAL,
                    getBundlePropertyFile().getString("sale.noprint.title"),
                    getBundlePropertyFile().getString("sale.noprint.exception.desc"));
        }

    }
    
    public void autorizarPendingInvoice() {
        logger.info("noPrintSale");

        try {
            boolean success = getController().autorizarInvoice(getSelectedInvoiceAuth().getId(),getLoggedUser());

            if (success) {
                setSelectedExpenseAuth(null);

                showMessage(FacesMessage.SEVERITY_INFO,
                        "Autorizar",
                        "Se autorizó correctamente");
               setInvoiceAuth(getController().getInvoiceNoPaidPending(getLoggedUser().getLocation().getId()));
            } else {
                logger.error("Sale " + getSelectedExpenseAuth() + "was not changed to no print");
                showMessage(FacesMessage.SEVERITY_ERROR,
                        "Autorizar",
                        "No se pudo autorizar");
            }

        } catch (Exception e) {
            logger.error("autorizar: " + e);

            showMessage(FacesMessage.SEVERITY_FATAL,
                    getBundlePropertyFile().getString("sale.noprint.title"),
                    getBundlePropertyFile().getString("sale.noprint.exception.desc"));
        }

    }
    
    public void autorizarPendingPaymentClient() {
        logger.info("noPrintSale");

        try {
            boolean success = getController().autorizarPaymentClient(getSelectedPaymentClientAuth().getId(),getLoggedUser());

            if (success) {
                setSelectedExpenseAuth(null);

                showMessage(FacesMessage.SEVERITY_INFO,
                        "Autorizar",
                        "Se autorizó correctamente");
               setPaymentClientAuth(getController().getPaymentClientNoPaidPending(getLoggedUser().getLocation().getId()));
            } else {
                logger.error("Sale " + getSelectedExpenseAuth() + "was not changed to no print");
                showMessage(FacesMessage.SEVERITY_ERROR,
                        "Autorizar",
                        "No se pudo autorizar");
            }

        } catch (Exception e) {
            logger.error("autorizar: " + e);

            showMessage(FacesMessage.SEVERITY_FATAL,
                    getBundlePropertyFile().getString("sale.noprint.title"),
                    getBundlePropertyFile().getString("sale.noprint.exception.desc"));
        }

    }
    
    public void autorizar() {
        logger.info("autorizar");
        if(getGenericController().existStableGeneralBoxByCurdate(getLoggedUser()))
            {
                showMessage(FacesMessage.SEVERITY_WARN,
                            "Dia cerrado",
                            "No se pueden autorizar más transferencia porque ya existe un cuadre de caja general del día");
                return;
            }
        
        if (getController().updateTransferMoneyLocationById(selectedRow.getId(), BasicType.ENEBLED, getLoggedUser()))
            {
               showMessage(FacesMessage.SEVERITY_INFO,
                        "Transferencia de dinero",
                        "Se autorizó correctamente");
               
               setUpDates(false);
               setTransfer(
                        getController().findTransferMoneyLocationBetweenDates(
                                getStartDate(),
                                getEndDate(),
                                getLoggedUser().getLocation().getId()));
            }
        
    }

    @Override
    public void addRow() {
        logger.info("addRow");
        if(getGenericController().existStableGeneralBoxByCurdate(getLoggedUser()))
            {
                showMessage(FacesMessage.SEVERITY_WARN,
                            "Dia cerrado",
                            "No se pueden generar más transferencia porque ya existe un cuadre de caja general del día");
                return;
            }
        try {
            
            getNewTransfer().setId(UUID.randomUUID().toString());
            getNewTransfer().setActive(true);
            getNewTransfer().setAutorizacion(BasicType.DISABLED);
            getNewTransfer().setCreatedBy(getLoggedUser());
            getNewTransfer().setCreatedOn(new Date());
            getNewTransfer().setLocation(getLoggedUser().getLocation());
            getNewTransfer().setLocationSend(getLoggedUser().getLocation());
            getNewTransfer().setLocationReceiver(new Location(locationId));
            getNewTransfer().setAmount(totalAmount);
            getNewTransfer().setAmountExpense(amountIngresosEgresos);
            getNewTransfer().setAmountInvoice(amountCompras);
            getNewTransfer().setAmountPaymentClient(amountPagos);

            if (getController().save(getNewTransfer())) {
                setUpDates(false);
                amountIngresosEgresos = 0D;
                amountCompras = 0D;
                amountPagos = 0D;
                totalAmount = 0D;
                setTransfer(
                        getController().findTransferMoneyLocationBetweenDates(
                                getStartDate(),
                                getEndDate(),
                                getLoggedUser().getLocation().getId())
                );
                
                if (!getSelectedInvoice().isEmpty()) {
                    for(Invoice tmp: getSelectedInvoice()){
                        getController().updateInvoiceSetPaid(tmp.getId(), getLoggedUser());
                    }
                }
                
                if (!getSelectedExpenseToPay().isEmpty()) {
                    for(Expense tmp: getSelectedExpenseToPay()){
                        getController().updateExpenseSetPaid(tmp.getId(), getLoggedUser());
                    }
                }
                
                if (!getSelectedPaymentClientToPay().isEmpty()) {
                    for(PaymentClient tmp: getSelectedPaymentClientToPay()){
                        getController().updatePaymentClientSetPaid(tmp.getId(), getLoggedUser());
                    }
                }
                setInvoice(getController().getInvoiceNoPaid(getLoggedUser().getLocation().getId()));
                setPaymentClient(getController().getPaymentClientNoPaid(getLoggedUser().getLocation().getId()));
                setExpense(getController().getExpenseNoPaid(getLoggedUser().getLocation().getId()));

                showMessage(FacesMessage.SEVERITY_INFO,
                        "Transferencia de dinero",
                        "Se creó correctamente");
            } else {
                showMessage(FacesMessage.SEVERITY_ERROR,
                        "Transferencia de dinero",
                        getBundlePropertyFile().getString("payment.in.add.exception.desc"));
            }
        } catch (Exception e) {
            logger.error("addRow", e);
            showMessage(FacesMessage.SEVERITY_ERROR,
                    "Transferencia de dinero",
                    getBundlePropertyFile().getString("payment.in.add.exception.desc"));
        }
    }

    @Override
    public void deleteRow() {
        if (getController().deleteTransferMoneyLocationById(getSelectedRow().getId(), getLoggedUser())) {
            showMessage(FacesMessage.SEVERITY_INFO,
                        "Transferencia de dinero",
                        "Se eliminó correctamente");
        }
        else
        {
           showMessage(FacesMessage.SEVERITY_ERROR,
                    "Transferencia de dinero",
                    getBundlePropertyFile().getString("payment.in.add.exception.desc")); 
        }
    }

    /**
     * Setup start date and end date.
     *
     * @param init True if comes from @PostConstruct otherwise false.
     */
    private void setUpDates(boolean init) {
        Calendar startCalendar = Calendar.getInstance();
        Calendar endCalendar = Calendar.getInstance();

        if (!init) {
            startCalendar.setTime(getStartDate());
            endCalendar.setTime(getEndDate());
        } else {
            startCalendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
            endCalendar.setTime(new Date());
        }

        startCalendar.add(Calendar.HOUR_OF_DAY, 2);
        startCalendar.add(Calendar.MINUTE, 0);
        startCalendar.add(Calendar.SECOND, 0);
        startCalendar.add(Calendar.MILLISECOND, 0);

        endCalendar.add(Calendar.HOUR_OF_DAY, 22);
        endCalendar.add(Calendar.MINUTE, 59);
        endCalendar.add(Calendar.SECOND, 59);
        endCalendar.add(Calendar.MILLISECOND, 0);

        setStartDate(startCalendar.getTime());
        setEndDate(endCalendar.getTime());
    }
    
    public float getCalculatePaymentPrice() {
        float zero = 0f;
        if (!getSelectedPaymentClientToPay().isEmpty()) {
            zero = getSelectedPaymentClientToPay()
                    .stream()
                    .map(row -> row.getTotalPayment().floatValue())
                    .reduce(zero, (accumulator, _item) -> accumulator + _item);
        }
        amountPagos = zero;
        return zero;
    }
    
    public float getCalculateInvoicePrice() {
        float zero = 0f;
        if (!getSelectedInvoice().isEmpty()) {
            zero = getSelectedInvoice()
                    .stream()
                    .map(row -> row.getTotal().floatValue())
                    .reduce(zero, (accumulator, _item) -> accumulator + _item);
        }
        amountCompras = zero;
        return zero;
    }
    
    public float getCalculateExpensePrice() {
        float zero = 0f;
        if (!getSelectedExpenseToPay().isEmpty()) {
            zero = getSelectedExpenseToPay()
                    .stream()
                    .map(row -> row.getPayment().floatValue())
                    .reduce(zero, (accumulator, _item) -> accumulator + _item);
        }
        amountIngresosEgresos = zero;
        return zero;
    }

    public void calculateTotalPayment() {
        try {
            
            totalAmount = getCalculatePaymentPrice() + getCalculateInvoicePrice() + getCalculateExpensePrice();

            PrimeFaces.current().ajax().update("sanctionForm:totalAmount");
        } catch (Exception e) {
            logger.error("calculateTotalFinancing", e);
            showMessage(FacesMessage.SEVERITY_ERROR, "Pago al cliente", "Error calculando el total financiado");
        }
    }

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

            setController(new TransferMoneyLocationController());
            setBitacoraController(new BitacoraController());
            setCreatedOn(new Date());
            setGenericController(new GenericValidationController());
            setLastStableGeneralBox(getGenericController().lastStableGeneralBoxByDate(getLoggedUser()));
            setHayCuadre(getGenericController().existStableGeneralBoxByCurdate(getLoggedUser()));
            setIdLocation(getLoggedUser().getLocation().getId());
            
            newTransfer = new TransferMoneyLocation();
            setLocation(getController().findLocation(getLoggedUser().getLocation()));
            
            setInvoice(getController().getInvoiceNoPaid(getLoggedUser().getLocation().getId()));
            setPaymentClient(getController().getPaymentClientNoPaid(getLoggedUser().getLocation().getId()));
            setExpense(getController().getExpenseNoPaid(getLoggedUser().getLocation().getId()));
            setExpenseAuth(getController().getExpenseNoPaidPending(getLoggedUser().getLocation().getId()));
            setInvoiceAuth(getController().getInvoiceNoPaidPending(getLoggedUser().getLocation().getId()));
            setPaymentClientAuth(getController().getPaymentClientNoPaidPending(getLoggedUser().getLocation().getId()));

                setUpDates(true);
                setTransfer(
                        getController().findTransferMoneyLocationBetweenDates(
                                getStartDate(),
                                getEndDate(),
                                getLoggedUser().getLocation().getId()));
            
        } catch (Exception e) {
            logger.error(e);
        }
    }

    private TransferMoneyLocationController controller;
    private List<TransferMoneyLocation> transfer;
    private TransferMoneyLocation selectedRow;
    private TransferMoneyLocation newTransfer;
    private Date startDate;
    private Date endDate;
    private Date createdOn;
    private BitacoraController bitacoraController;
    private String commentsBitacora;
    private GenericValidationController genericController;
    private Date lastStableGeneralBox;
    private boolean hayCuadre;
    private String locationId;
    private List<Location> location;
    private String idLocation; 
    private double amountCompras;
    private double amountPagos;
    private double amountIngresosEgresos;
    private double totalAmount;
    
    private List<Invoice> invoice = new ArrayList<>();
    private List<Invoice> selectedInvoice;
    private List<PaymentClient> paymentClient = new ArrayList<>();
    private List<PaymentClient> selectedPaymentClientToPay;
    private List<Expense> expense = new ArrayList<>();
    private List<Expense> expenseAuth = new ArrayList<>();
    private List<Invoice> invoiceAuth = new ArrayList<>();
    private List<PaymentClient> paymentClientAuth = new ArrayList<>();
    
    private List<Expense> selectedExpenseToPay;
    private Expense selectedExpenseAuth;
    private Invoice selectedInvoiceAuth;
    private PaymentClient selectedPaymentClientAuth;

    public List<Expense> getExpense() {
        return expense;
    }

    public void setExpense(List<Expense> expense) {
        this.expense = expense;
    }

    public List<Expense> getSelectedExpenseToPay() {
        if (null == selectedExpenseToPay) {
            selectedExpenseToPay = new ArrayList<>();
        }
        return selectedExpenseToPay;
    }

    public void setSelectedExpenseToPay(List<Expense> selectedExpenseToPay) {
        this.selectedExpenseToPay = selectedExpenseToPay;
    }

    public List<PaymentClient> getSelectedPaymentClientToPay() {
        if (null == selectedPaymentClientToPay) {
            selectedPaymentClientToPay = new ArrayList<>();
        }
        return selectedPaymentClientToPay;
    }

    public void setSelectedPaymentClientToPay(List<PaymentClient> selectedPaymentClientToPay) {
        this.selectedPaymentClientToPay = selectedPaymentClientToPay;
    }

    public List<Invoice> getSelectedInvoice() {
        if (null == selectedInvoice) {
            selectedInvoice = new ArrayList<>();
        }
        return selectedInvoice;
    }

    public void setSelectedInvoice(List<Invoice> selectedInvoice) {
        this.selectedInvoice = selectedInvoice;
    }

    public List<Invoice> getInvoice() {
        return invoice;
    }

    public void setInvoice(List<Invoice> invoice) {
        this.invoice = invoice;
    }

    public List<PaymentClient> getPaymentClient() {
        return paymentClient;
    }

    public void setPaymentClient(List<PaymentClient> paymentClient) {
        this.paymentClient = paymentClient;
    }

    public double getTotalAmount() {
        return totalAmount;
    }

    public void setTotalAmount(double totalAmount) {
        this.totalAmount = totalAmount;
    }

    public double getAmountCompras() {
        return amountCompras;
    }

    public void setAmountCompras(double amountCompras) {
        this.amountCompras = amountCompras;
    }

    public double getAmountPagos() {
        return amountPagos;
    }

    public void setAmountPagos(double amountPagos) {
        this.amountPagos = amountPagos;
    }

    public double getAmountIngresosEgresos() {
        return amountIngresosEgresos;
    }

    public void setAmountIngresosEgresos(double amountIngresosEgresos) {
        this.amountIngresosEgresos = amountIngresosEgresos;
    }

    public String getIdLocation() {
        return idLocation;
    }

    public void setIdLocation(String idLocation) {
        this.idLocation = idLocation;
    }

    public TransferMoneyLocation getNewTransfer() {
        return newTransfer;
    }

    public void setNewTransfer(TransferMoneyLocation newTransfer) {
        this.newTransfer = newTransfer;
    }

    public String getLocationId() {
        return locationId;
    }

    public void setLocationId(String locationId) {
        this.locationId = locationId;
    }

    public List<Location> getLocation() {
        return location;
    }

    public void setLocation(List<Location> location) {
        this.location = location;
    }

    public TransferMoneyLocationController getController() {
        return controller;
    }

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

    public List<TransferMoneyLocation> getTransfer() {
        return transfer;
    }

    public void setTransfer(List<TransferMoneyLocation> transfer) {
        this.transfer = transfer;
    }

    public TransferMoneyLocation getSelectedRow() {
        return selectedRow;
    }

    public void setSelectedRow(TransferMoneyLocation selectedRow) {
        this.selectedRow = selectedRow;
    }

    public Date getStartDate() {
        return startDate;
    }

    public void setStartDate(Date startDate) {
        this.startDate = startDate;
    }

    public Date getEndDate() {
        return endDate;
    }

    public void setEndDate(Date endDate) {
        this.endDate = endDate;
    }

    public Date getCreatedOn() {
        return createdOn;
    }

    public void setCreatedOn(Date createdOn) {
        this.createdOn = createdOn;
    }

    public BitacoraController getBitacoraController() {
        return bitacoraController;
    }

    public void setBitacoraController(BitacoraController bitacoraController) {
        this.bitacoraController = bitacoraController;
    }

    public String getCommentsBitacora() {
        return commentsBitacora;
    }

    public void setCommentsBitacora(String commentsBitacora) {
        this.commentsBitacora = commentsBitacora;
    }

    public GenericValidationController getGenericController() {
        return genericController;
    }

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

    public Date getLastStableGeneralBox() {
        return lastStableGeneralBox;
    }

    public void setLastStableGeneralBox(Date lastStableGeneralBox) {
        this.lastStableGeneralBox = lastStableGeneralBox;
    }

    public boolean isHayCuadre() {
        return hayCuadre;
    }

    public void setHayCuadre(boolean hayCuadre) {
        this.hayCuadre = hayCuadre;
    }

    public List<Expense> getExpenseAuth() {
        return expenseAuth;
    }

    public void setExpenseAuth(List<Expense> expenseAuth) {
        this.expenseAuth = expenseAuth;
    }

    public Expense getSelectedExpenseAuth() {
        return selectedExpenseAuth;
    }

    public void setSelectedExpenseAuth(Expense selectedExpenseAuth) {
        this.selectedExpenseAuth = selectedExpenseAuth;
    }

    public List<Invoice> getInvoiceAuth() {
        return invoiceAuth;
    }

    public void setInvoiceAuth(List<Invoice> invoiceAuth) {
        this.invoiceAuth = invoiceAuth;
    }

    public Invoice getSelectedInvoiceAuth() {
        return selectedInvoiceAuth;
    }

    public void setSelectedInvoiceAuth(Invoice selectedInvoiceAuth) {
        this.selectedInvoiceAuth = selectedInvoiceAuth;
    }

    public List<PaymentClient> getPaymentClientAuth() {
        return paymentClientAuth;
    }

    public void setPaymentClientAuth(List<PaymentClient> paymentClientAuth) {
        this.paymentClientAuth = paymentClientAuth;
    }

    public PaymentClient getSelectedPaymentClientAuth() {
        return selectedPaymentClientAuth;
    }

    public void setSelectedPaymentClientAuth(PaymentClient selectedPaymentClientAuth) {
        this.selectedPaymentClientAuth = selectedPaymentClientAuth;
    }
    
    
    

    
    private static final long serialVersionUID = 7328275333340376725L;
    final Logger logger = LogManager.getLogger(TransferMoneyLocationBean.class);

}
