/*
 * 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.apc.web.beans.admin.people;

import com.arrebol.apc.model.catalog.People;
import com.arrebol.apc.model.catalog.RouteCtlg;
import com.arrebol.apc.model.core.Office;
import com.arrebol.apc.model.core.User;
import com.arrebol.apc.model.enums.ActiveStatus;
import com.arrebol.apc.model.enums.CustomerClassification;
import com.arrebol.apc.model.enums.LoanDetailsType;
import com.arrebol.apc.model.enums.LoanStatus;
import com.arrebol.apc.model.enums.OwnerLoan;
import com.arrebol.apc.model.enums.PeopleType;
import com.arrebol.apc.model.loan.Loan;
import com.arrebol.apc.model.loan.LoanByUser;
import com.arrebol.apc.model.loan.LoanByUserId;
import com.arrebol.apc.model.loan.LoanDetails;
import com.arrebol.apc.model.loan.LoanType;
import com.arrebol.apc.model.system.logs.Bitacora;
import com.arrebol.apc.model.views.CustomerView;
import com.arrebol.apc.service.BitacoraService;
import com.arrebol.apc.service.admin.CustomerService;
import com.arrebol.apc.service.admin.PeopleService;
import com.arrebol.apc.service.catalog.LoanService;
import com.arrebol.apc.service.catalog.LoanTypeService;
import com.arrebol.apc.service.catalog.PeopleAutoCompleteService;
import com.arrebol.apc.service.catalog.RouteService;
import com.arrebol.apc.service.core.UserService;
import com.arrebol.apc.web.beans.GenericBean;
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.Map;
import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.view.ViewScoped;
import javax.inject.Inject;
import javax.inject.Named;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.primefaces.model.LazyDataModel;
import org.primefaces.model.SortOrder;

/**
 *
 * @author Carlos Janitzio Zavala Lopez <janitzio.zavala@arrebol.com.mx>
 */
@Named(value = "personCustomerBean")
@ViewScoped
public class PersonCustomerBean extends GenericBean implements Serializable {

    /**
     *
     * @param query
     * @return
     */
    public List<People> completeCustomer(String query) {
        return peopleAutoCompleteService.findCustomersLike(query.trim());
    }

    /**
     *
     * @param query
     * @return
     */
    public List<People> completeEndorsement(String query) {
        return peopleAutoCompleteService.findEndorsementsLike(query.trim());
    }

    /**
     *
     */
    public void changeRoute() {
        if (!getRouteId().isEmpty()) {
            if (customerService.updateRouteById(new RouteCtlg(getRouteId()), getSelectedCustomerView().getId(), getLoggedUser().getUser().getId())) {
                showMessage(FacesMessage.SEVERITY_INFO, "Cliente", "Se modificó la ruta del cliente correctamente.");
            } else {
                showMessage(FacesMessage.SEVERITY_WARN, "Cliente", "Ocurrió un error durante el proceso de modificacipon de la ruta del cliente.");
            }
        }
    }

    /**
     *
     */
    public void deleteRow() {
        try {
            customerService.updatePeopleByStatus(ActiveStatus.DISABLED, getSelectedCustomerView().getId(), getLoggedUser().getUser().getId());

            setSelectedCustomerView(null);
            showMessage(FacesMessage.SEVERITY_INFO, "Cliente", "Se eliminó correctamente.");
        } catch (Exception e) {
            showMessage(FacesMessage.SEVERITY_ERROR, "Cliente", "No se eliminó correctamente.");
        }
    }

    /**
     *
     */
    public void updatePeopleTypeById() {
        if (getSelectedCustomerView().getPeopleType().equals(PeopleType.BOTH)) {
            showMessage(FacesMessage.SEVERITY_WARN, "Advertencia", "El cliente ya se encuentra como Aval.");
            return;
        }
        try {
            customerService.updatePeopleTypeById(PeopleType.BOTH, getSelectedCustomerView().getId(), getLoggedUser().getUser().getId());
            setSelectedCustomerView(null);
            // TODO cargar de nuevo el lazy data model para poder actualizar la datatable
            showMessage(FacesMessage.SEVERITY_INFO, "Cliente", "Se modificó correctamente.");
        } catch (Exception e) {
            logger.error("updatePeopleTypeById", e);
            showMessage(FacesMessage.SEVERITY_INFO, "Cliente", "No se modificó correctamente.");
        }
    }

    /**
     *
     * @param outcome
     * @return
     */
    public String detailCustomer(String outcome) {
        return outcome;
    }

    /**
     *
     */
    public void calculationFunction() {
        if (loanTypeId != null && !loanTypeId.isEmpty()) {
            total = loanTypeService.getLoanTypeById(loanTypeId).getPaymentTotal().add(totalFee).subtract(totalPayment);
        } else {
            total = BigDecimal.ZERO;
        }
    }

    /**
     *
     */
    public void addRow() {
        try {
            Loan loanSave = new Loan();
            loanSave.setComments(getComments());
            loanSave.setCustomer(getAutoCompleteCustomer());
            loanSave.setEndorsement(getAutoCompleteEndorsement());
            loanSave.setLoanType(new LoanType(getLoanTypeId()));
            if (isAprobado()) {
                loanSave.setLoanStatus(LoanStatus.APPROVED);
            } else if (isTerminado()) {
                loanSave.setLoanStatus(LoanStatus.FINISH);
            } else {
                loanSave.setLoanStatus(LoanStatus.PENDING);
            }
            loanSave.setAmountPaid(getTotalPayment());
            loanSave.setRouteCtlg(peopleService.findPeopleById(getAutoCompleteCustomer().getId()).getRouteCtlg());
            if (getTotalPayment().compareTo(BigDecimal.ZERO) == 0 && getTotalFee().compareTo(BigDecimal.ZERO) == 0) {
                loanSave.setLastReferenceNumber(0);
            }
            if (getTotalPayment().compareTo(BigDecimal.ZERO) > 0 && getTotalFee().compareTo(BigDecimal.ZERO) == 0) {
                loanSave.setLastReferenceNumber(1);
            }
            if (getTotalPayment().compareTo(BigDecimal.ZERO) == 0 && getTotalFee().compareTo(BigDecimal.ZERO) > 0) {
                loanSave.setLastReferenceNumber(1);
            }
            if (getTotalPayment().compareTo(BigDecimal.ZERO) > 0 && getTotalFee().compareTo(BigDecimal.ZERO) > 0) {
                loanSave.setLastReferenceNumber(2);
            }
            loanSave.setAmountToPay(loanTypeService.getLoanTypeById(getLoanTypeId()).getPaymentTotal().add(getTotalFee()));
            loanSave.setCreatedBy(getUserId());
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(getCreatedOn());
            calendar.set(Calendar.HOUR_OF_DAY, 12);
            calendar.set(Calendar.MINUTE, 0);
            calendar.set(Calendar.SECOND, 0);
            calendar.set(Calendar.MILLISECOND, 0);
            loanSave.setCreatedOn(new Date());
            loanSave.setLastUpdatedOn(new Date());

            if (loanService.saveLoan(loanSave)) {
                Loan temp = loanService.getLoanById(loanSave.getId());
                String userName = "";
                for (User user : getUsers()) {
                    if (user.getId().equalsIgnoreCase(getUserId())) {
                        userName = user.getHumanResource().getFirstName() + " "
                                + user.getHumanResource().getLastName();
                        break;
                    }
                }
                Calendar fechaAct = Calendar.getInstance();
                if (fechaAct.before(calendar)) {
                    Bitacora bitacora = new Bitacora();
                    bitacora.setAction("Préstamo postfechado");
                    bitacora.setCommentsUser("");
                    bitacora.setCreatedBy(getLoggedUser().getUser().getId());
                    bitacora.setCreatedOn(new Date());
                    bitacora.setDescription("El usuario " + userName + " postfechó el préstamo del cliente " + temp.getCustomer().getFullName()
                            + ", con cantidad de $" + temp.getLoanType().getPayment() + " al día " + temp.getCreatedOn());
                    bitacora.setNameUser(getLoggedUser().getUser().getUserName());
                    bitacora.setOffice(new Office(getLoggedUser().getOffice().getId()));
                    bitacoraService.saveBitacora(bitacora);
                }

                LoanByUser loanByUser = new LoanByUser();
                LoanByUserId idRelation = new LoanByUserId();

                idRelation.setIdLoan(loanSave.getId());
                idRelation.setIdUser(getUserId());

                loanByUser.setId(idRelation);
                loanByUser.setComments(getComments());
                loanByUser.setCreatedBy(getLoggedUser().getUser().getId());
                if (isAprobado()) {
                    loanByUser.setLoanByUserStatus(LoanStatus.APPROVED);
                } else if (isTerminado()) {
                    loanByUser.setLoanByUserStatus(LoanStatus.FINISH);
                } else {
                    loanByUser.setLoanByUserStatus(LoanStatus.PENDING);
                }
                loanByUser.setLoan(loanSave);
                loanByUser.setOrderInList(0);
                loanByUser.setOwnerLoan(OwnerLoan.CURRENT_OWNER);
                loanByUser.setUser(new User(getUserId()));
                loanService.saveLoanByUser(loanByUser);

                int contador = 1;
                if (getTotalPayment().compareTo(BigDecimal.ZERO) > 0) {
                    LoanDetails detail = new LoanDetails();
                    detail.setComments(getComments());
                    detail.setCreatedBy(getLoggedUser().getUser().getId());
                    detail.setCreatedOn(getCreatedOn());
                    detail.setLoan(loanSave);
                    detail.setLoanDetailsType(LoanDetailsType.PAYMENT);
                    detail.setPaymentAmount(getTotalPayment());
                    detail.setPeopleType(PeopleType.CUSTOMER);
                    detail.setReferenceNumber(contador);
                    detail.setUser(new User(getUserId()));
                    if (loanService.saveLoanDetail(detail)) {
                        contador++;
                    }
                }
                if (getTotalFee().compareTo(BigDecimal.ZERO) > 0) {
                    LoanDetails detail = new LoanDetails();
                    detail.setComments(getComments());
                    detail.setCreatedBy(getLoggedUser().getUser().getId());
                    detail.setCreatedOn(getCreatedOn());
                    detail.setLoan(loanSave);
                    detail.setLoanDetailsType(LoanDetailsType.FEE);
                    detail.setPaymentAmount(getTotalFee());
                    detail.setPeopleType(PeopleType.CUSTOMER);
                    detail.setReferenceNumber(contador);
                    detail.setUser(new User(getUserId()));
                    if (loanService.saveLoanDetail(detail)) {
                        contador++;
                    }
                }

            }
            //loan.clear();
            setCreatedOn(new Date());
            setComments("");
            //customerId = "";
            //endorsementId = "";
            setLoanTypeId("");
            setUserId("");
            setTotal(BigDecimal.ZERO);
            setTotalFee(BigDecimal.ZERO);
            setTotalPayment(BigDecimal.ZERO);
            setAprobado(false);
            setTerminado(false);
            setAutoCompleteCustomer(null);
            setAutoCompleteEndorsement(null);
            //loan = fillDatatableLoan();
            showMessage(FacesMessage.SEVERITY_INFO, "Cliente", "Se agrego el prestamo al cliente correctamente.");
        } catch (Exception e) {
            logger.error("", e);

            showMessage(FacesMessage.SEVERITY_INFO, "Cliente", "No se agrego el nuevo prestamos al cliente.");
        }
    }

    /**
     *
     */
    public void addPeople() {
        try {
            logger.debug("addPeople");
            
            getSavePeople().setCreatedBy(getLoggedUser().getUser().getId());
            getSavePeople().setOffice(new Office(getLoggedUser().getOffice().getId()));
            getSavePeople().setActiveStatus(ActiveStatus.ENEBLED);
            getSavePeople().setRouteCtlg(new RouteCtlg(routeId));
            getSavePeople().setThumbnail("");
            getSavePeople().setClassification(CustomerClassification.WHITE);

            if (isCustomer() == true && isEndorsement() == false) {
                getSavePeople().setPeopleType(PeopleType.CUSTOMER);
            }
            if (isCustomer() == true && isEndorsement() == true) {
                getSavePeople().setPeopleType(PeopleType.BOTH);
            }
            if (isCustomer() == false && isEndorsement() == true) {
                getSavePeople().setPeopleType(PeopleType.ENDORSEMENT);
            }
            if (isCustomer() == false && isEndorsement() == false) {
                getSavePeople().setPeopleType(PeopleType.BOTH);
            }

            String messafeFormat = getBundlePropertyFile().getString("message.format.failure");
            FacesMessage.Severity severity = FacesMessage.SEVERITY_WARN;

            if (peopleService.savePeople(getSavePeople())) {
                setSavePeople(new People());
                setCustomer(false);
                setEndorsement(false);
                messafeFormat = getBundlePropertyFile().getString("message.format.sucess");
                severity = FacesMessage.SEVERITY_INFO;
            }

            Object[] param = {getBundlePropertyFile().getString("people"), getBundlePropertyFile().getString("created")};

            buildAndSendMessage(param, messafeFormat, severity, getBundlePropertyFile().getString("people"));

        } catch (Exception e) {
            logger.error("savePeople", e);
            Object[] param = {getBundlePropertyFile().getString("created")};

            buildAndSendMessage(
                    param,
                    getBundlePropertyFile().getString("message.format.fatal"),
                    FacesMessage.SEVERITY_FATAL,
                    getBundlePropertyFile().getString("people")
            );
        }
    }

    /**
     *
     */
    private void loadingLazyDataTable() {
        try {
            setCustomerViews(new LazyDataModel<CustomerView>() {
                private List<CustomerView> lazyEntityList;

                @Override
                public List<CustomerView> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, Object> filterBy) {
                    try {
                        Long total = customerService.countPaginator(filterBy);

                        setRowCount(total.intValue());

                        lazyEntityList = customerService.lazyEntityListPaginator(first, pageSize, sortField, sortOrder, filterBy);

                        return lazyEntityList;
                    } catch (Exception e) {
                        logger.error("lazy Entity List", e);
                        setRowCount(0);
                        return new ArrayList<>();
                    }
                }

                @Override
                public String getRowKey(CustomerView row) {
                    return row.getId();
                }

                @Override
                public CustomerView getRowData(String rowKey) {
                    return lazyEntityList
                            .stream()
                            .filter(row -> rowKey.equals(row.getId()))
                            .findFirst()
                            .orElse(null);
                }
            }
            );
        } catch (Exception e) {
            logger.error("Lazy Data Model Customer View ", e);
        }
    }

    public void CustomerClassification(String colorClassification)
    {
        try {
            customerService.updatePeopleByClassification( CustomerClassification.valueOf(colorClassification), getSelectedCustomerView().getId(), getLoggedUser().getUser().getId());

            setSelectedCustomerView(null);
            showMessage(FacesMessage.SEVERITY_INFO, "Cliente", "Se clasificó correctamente.");
        } catch (Exception e) {
            showMessage(FacesMessage.SEVERITY_ERROR, "Cliente", "No se clasificó correctamente.");
        }
    }
    
    @PostConstruct
    public void init() {
        try {
            loadBundlePropertyFile();
            loadingLazyDataTable();
            setRoutes(routeService.fillRoutesDatatable(getLoggedUser().getOffice().getId()));
            setLoanType(loanTypeService.fillLoanTypeDatatable(getLoggedUser().getOffice().getId()));
            setUsers(userService.getAllUsersByOffice(getLoggedUser().getOffice().getId()));
            setTotalPayment(BigDecimal.ZERO);
            setTotalFee(BigDecimal.ZERO);
            setTotal(BigDecimal.ZERO);
            setSavePeople(new People());
        } catch (Exception e) {
            logger.error("PersonCustomerBean init", e);
        }
    }

    final Logger logger = LogManager.getLogger(getClass());

    @Inject
    private CustomerService customerService;
    @Inject
    private PeopleService peopleService;
    @Inject
    private RouteService routeService;
    @Inject
    private LoanTypeService loanTypeService;
    @Inject
    private LoanService loanService;
    @Inject
    private BitacoraService bitacoraService;
    @Inject
    private UserService userService;
    @Inject
    private PeopleAutoCompleteService peopleAutoCompleteService;

    private LazyDataModel<CustomerView> customerViews;
    private CustomerView selectedCustomerView;
    private List<People> customers;
    private List<RouteCtlg> routes;
    private String routeId;
    private String comments;

    private People autoCompleteCustomer;
    private People autoCompleteEndorsement;
    private People savePeople;
    private List<LoanType> loanType;
    private List<User> users;

    private String customerId;
    private String endorsementId;
    private String loanTypeId;
    private String userId;

    private Date createdOn;
    private BigDecimal totalPayment;
    private BigDecimal totalFee;
    private BigDecimal total;
    private boolean aprobado;
    private boolean terminado;
    boolean customer;
    boolean endorsement;

    public LazyDataModel<CustomerView> getCustomerViews() {
        return customerViews;
    }

    public void setCustomerViews(LazyDataModel<CustomerView> customerViews) {
        this.customerViews = customerViews;
    }

    public CustomerView getSelectedCustomerView() {
        return selectedCustomerView;
    }

    public void setSelectedCustomerView(CustomerView selectedCustomerView) {
        this.selectedCustomerView = selectedCustomerView;
    }

    public List<People> getCustomers() {
        return customers;
    }

    public void setCustomers(List<People> customers) {
        this.customers = customers;
    }

    public List<RouteCtlg> getRoutes() {
        return routes;
    }

    public void setRoutes(List<RouteCtlg> routes) {
        this.routes = routes;
    }

    public String getRouteId() {
        return routeId;
    }

    public void setRouteId(String routeId) {
        this.routeId = routeId;
    }

    public String getComments() {
        return comments;
    }

    public void setComments(String comments) {
        this.comments = comments;
    }

    public List<LoanType> getLoanType() {
        return loanType;
    }

    public void setLoanType(List<LoanType> loanType) {
        this.loanType = loanType;
    }

    public List<User> getUsers() {
        return users;
    }

    public void setUsers(List<User> users) {
        this.users = users;
    }

    public String getCustomerId() {
        return customerId;
    }

    public void setCustomerId(String customerId) {
        this.customerId = customerId;
    }

    public String getEndorsementId() {
        return endorsementId;
    }

    public void setEndorsementId(String endorsementId) {
        this.endorsementId = endorsementId;
    }

    public String getLoanTypeId() {
        return loanTypeId;
    }

    public void setLoanTypeId(String loanTypeId) {
        this.loanTypeId = loanTypeId;
    }

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public Date getCreatedOn() {
        return createdOn;
    }

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

    public BigDecimal getTotalPayment() {
        return totalPayment;
    }

    public void setTotalPayment(BigDecimal totalPayment) {
        this.totalPayment = totalPayment;
    }

    public BigDecimal getTotalFee() {
        return totalFee;
    }

    public void setTotalFee(BigDecimal totalFee) {
        this.totalFee = totalFee;
    }

    public BigDecimal getTotal() {
        return total;
    }

    public void setTotal(BigDecimal total) {
        this.total = total;
    }

    public boolean isAprobado() {
        return aprobado;
    }

    public void setAprobado(boolean aprobado) {
        this.aprobado = aprobado;
    }

    public boolean isTerminado() {
        return terminado;
    }

    public void setTerminado(boolean terminado) {
        this.terminado = terminado;
    }

    public People getAutoCompleteCustomer() {
        return autoCompleteCustomer;
    }

    public void setAutoCompleteCustomer(People autoCompleteCustomer) {
        this.autoCompleteCustomer = autoCompleteCustomer;
    }

    public People getAutoCompleteEndorsement() {
        return autoCompleteEndorsement;
    }

    public void setAutoCompleteEndorsement(People autoCompleteEndorsement) {
        this.autoCompleteEndorsement = autoCompleteEndorsement;
    }

    public People getSavePeople() {
        return savePeople;
    }

    public void setSavePeople(People savePeople) {
        this.savePeople = savePeople;
    }

    public boolean isCustomer() {
        return customer;
    }

    public void setCustomer(boolean customer) {
        this.customer = customer;
    }

    public boolean isEndorsement() {
        return endorsement;
    }

    public void setEndorsement(boolean endorsement) {
        this.endorsement = endorsement;
    }

}
