/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.arrebol.taxiservicios.beans.stocktaking.service.order;

import com.arrebol.taxiservicios.beans.TaxiGenericBean;
import com.arrebol.taxiservicios.controller.admin.ExpenseController;
import com.arrebol.taxiservicios.controller.admin.GenericValidationController;
import com.arrebol.taxiservicios.controller.admin.TaxiController;
import com.arrebol.taxiservicios.controller.catalog.LocationController;
import com.arrebol.taxiservicios.controller.stocktaking.ServiceOrderController;
import com.arrebol.taxiservicios.controller.stocktaking.ServiceOrderSingletonController;
import com.arrebol.taxiservicios.model.admin.Expense;
import com.arrebol.taxiservicios.model.admin.Taxi;
import com.arrebol.taxiservicios.model.catalog.Location;
import com.arrebol.taxiservicios.model.enums.BasicType;
import com.arrebol.taxiservicios.model.enums.ExpenseStatusType;
import com.arrebol.taxiservicios.model.enums.ExpenseType;
import com.arrebol.taxiservicios.model.enums.ServiceOrderActionType;
import com.arrebol.taxiservicios.model.enums.ServiceOrderType;
import com.arrebol.taxiservicios.model.stocktaking.ServiceOrder;
import com.arrebol.taxiservicios.model.stocktaking.ServiceOrderHasProduct;
import com.arrebol.taxiservicios.model.stocktaking.ServiceOrderNotification;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
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 oscarvargas
 */
@Named
@ViewScoped
public class ManagerBean extends TaxiGenericBean implements Serializable {

    public void changeToPendingServiceOrder() {
        logger.info("changeToPendingServiceOrder");
        try {
            if (getSingletonController().workWithServiceOrder(6, getSelectedServiceOrder().getId(), null, null, getLoggedUser().getId(), null, null, null, getLoggedUser().getLocation())) {

                loadServiceOrderList();

                showMessage(FacesMessage.SEVERITY_INFO,
                        getBundlePropertyFile().getString("manager.service.order"),
                        "Se cambio su estatus a pendiente");

            } else {
                logger.error("changeToPendingServiceOrder can not be change to status");
                showMessage(FacesMessage.SEVERITY_ERROR,
                        getBundlePropertyFile().getString("manager.service.order"),
                        "No se puede cambiar a estatus pendiente");
            }
        } catch (Exception e) {
            logger.error("changeToPendingServiceOrder", e);
            showMessage(FacesMessage.SEVERITY_FATAL,
                    getBundlePropertyFile().getString("manager.service.order"),
                    "No se puede cambiar a estatus pendiente");
        }
    }
    
    public void deleteServiceOrder() {
        logger.info("deleteServiceOrder");
        try {
            if (getSingletonController().workWithServiceOrder(3, getSelectedServiceOrder().getId(), null, null, null, null, null, null, getLoggedUser().getLocation())) {

                loadServiceOrderList();

                showMessage(FacesMessage.SEVERITY_INFO,
                        getBundlePropertyFile().getString("manager.service.order"),
                        getBundlePropertyFile().getString("manager.delete.service.order.desc"));

                ServiceOrderNotification notification = new ServiceOrderNotification(
                        UUID.randomUUID().toString(),
                        "Orden de servicio rechazada",
                        "Número de folio " + getSelectedServiceOrder().getName(),
                        new Date(),
                        ServiceOrderActionType.REJECTED);

                List<String> permissionLst = new ArrayList<>();

                permissionLst.add("stocktaking.service.order.garage.actions.btn.progress");

                ServiceOrderNotificationThread notificationThread
                        = new ServiceOrderNotificationThread(notification, permissionLst, getLoggedUser().getId()
                        );

                notificationThread.start();
            } else {
                logger.error("deleteServiceOrder can not be delete");
                showMessage(FacesMessage.SEVERITY_ERROR,
                        getBundlePropertyFile().getString("manager.service.order"),
                        getBundlePropertyFile().getString("manager.delete.service.order.error.desc"));
            }
        } catch (Exception e) {
            logger.error("deleteServiceOrder", e);
            showMessage(FacesMessage.SEVERITY_FATAL,
                    getBundlePropertyFile().getString("manager.service.order"),
                    getBundlePropertyFile().getString("manager.delete.service.order.exception.desc"));
        }
    }
    
    public void payServiceOrder(){
    logger.info("payServiceOrder");
        try {
            if (getSingletonController().workWithServiceOrder(7, getSelectedServiceOrder().getId(), null, null, getLoggedUser().getId(), null, null, null, getLoggedUser().getLocation())) {

                loadServiceOrderList();

                showMessage(FacesMessage.SEVERITY_INFO,"Orden de servicio pagada",
                        "Orden de servicio pagada");

                ServiceOrderNotification notification = new ServiceOrderNotification(
                        UUID.randomUUID().toString(),
                        "Orden de servicio Pagada",
                        "Número de folio " + getSelectedServiceOrder().getName(),
                        new Date(),
                        ServiceOrderActionType.PAYED);

                List<String> permissionLst = new ArrayList<>();

                permissionLst.add("stocktaking.service.order.garage.actions.btn.progress");

                ServiceOrderNotificationThread notificationThread
                        = new ServiceOrderNotificationThread(notification, permissionLst, getLoggedUser().getId()
                        );

                if(getController().payServiceOrderHasProduct(getSelectedServiceOrder().getId(), getLoggedUser().getId())){
                Expense expense = new Expense();
                expense.setId(UUID.randomUUID().toString());
                expense.setAmountMenudeo(getSelectedServiceOrder().getSubtotal().doubleValue());
                Calendar calendar = Calendar.getInstance();
                calendar.add(Calendar.HOUR, -6);
                expense.setCreatedOn(calendar.getTime());
                expense.setDescription("Pago orden de servicio " + getSelectedServiceOrder().getName());
                expense.setFolio("");
                expense.setPayment(getSelectedServiceOrder().getSubtotal().doubleValue());
                expense.setPaymentDate(calendar.getTime());
                expense.setStatus(ExpenseStatusType.AUTHORIZED);
                expense.setType(ExpenseType.PAGO_ORDEN_SERVICIO);
                expense.setLocation(getLoggedUser().getLocation());
                expense.setLocationSend(new Location(getLoggedUser().getId()));
                expense.setPaid(BasicType.ENEBLED);
                expense.setFinance(BasicType.DISABLED);
                expense.setServiceOrder(getSelectedServiceOrder());
                expense.setCommercialInvoiceStatus(BasicType.DISABLED);
                expense.setDepositStatus(ExpenseStatusType.AUTHORIZED);

                boolean success = getExpenseController().addExpense(
                        expense,
                        getLoggedUser().getId(),
                        (null != getSelectedServiceOrder().getTaxi().getId() && !"".equals(getSelectedServiceOrder().getTaxi().getId().trim())) ? getSelectedServiceOrder().getTaxi().getId() : null);

                if (success) {
                    
                    showMessage(FacesMessage.SEVERITY_INFO,
                            "Pgo de orden de servicio",
                            "Se agregó correctamente");
                }

                    logger.error("payServiceOrder payed");
                showMessage(FacesMessage.SEVERITY_INFO,"Se pagaron los productos",
                       "Se pagaron los productos");
                    }
                notificationThread.start();
            } else {
                logger.error("payServiceOrder can not be pay");
                showMessage(FacesMessage.SEVERITY_ERROR,"No se pudo pagar","No se pudo pagar la orden de servicio");
            }
        } catch (Exception e) {
            logger.error("deleteServiceOrder", e);
            showMessage(FacesMessage.SEVERITY_FATAL,"No se pudo pagar","No se pudo pagar la orden de servicio");
        }}

    public void authorizeServiceOrder() {
        logger.info("authorizeServiceOrder");
        try {
            if(getGenericController().existCheckStocktakingPending(getLoggedUser().getLocation().getId()))
        {
            showMessage(FacesMessage.SEVERITY_WARN,
                        "Inventario cerrado",
                        "No puedes hacer ningun movimiento al inventario hasta que se termine de cotejar");
            return;
        }
            Boolean[] greaterThan = {false};

            setDetails(getController().findAllProductByOrderId(getSelectedServiceOrder().getId()));

            if(getLoggedUser().getLocation().getId().equalsIgnoreCase("4d0859be-e31a-4acb-a690-2a5c2cb027a7"))
                {
                    getDetails()
                    .stream()
                    .filter(detail -> detail.getQuantity() > detail.getProduct().getQuantity())
                    .forEach((ServiceOrderHasProduct detail) -> {
                        greaterThan[0] = true;
                    });
                }
            else
            {
                getDetails()
                    .stream()
                    .filter(detail -> detail.getQuantity() > detail.getProduct().getQuantity2())
                    .forEach((ServiceOrderHasProduct detail) -> {
                        greaterThan[0] = true;
                    });
            }
            

            if (greaterThan[0]) {
                logger.error("Empty stock");
                showMessage(FacesMessage.SEVERITY_ERROR,
                        getBundlePropertyFile().getString("manager.service.order"),
                        getBundlePropertyFile().getString("manager.authorize.service.order.empty.stock"));
            } else if (getPending().equals(getSelectedServiceOrder().getServiceOrderType())) {

                if (getSingletonController().workWithServiceOrder(2, getSelectedServiceOrder().getId(),
                        getDetails(), null, getLoggedUser().getId(),
                        getSelectedServiceOrder().getTaxi().getId(), getSelectedServiceOrder().getKm(), getSelectedServiceOrder().getKmMaintenance(), 
                        getLoggedUser().getLocation())) {
                    loadServiceOrderList();

                    showMessage(FacesMessage.SEVERITY_INFO,
                            getBundlePropertyFile().getString("manager.service.order"),
                            getBundlePropertyFile().getString("manager.authorize.service.order"));

                    ServiceOrderNotification notification = new ServiceOrderNotification(
                            UUID.randomUUID().toString(),
                            "Orden de servicio aprobada",
                            "Número de folio " + getSelectedServiceOrder().getName(),
                            new Date(),
                            ServiceOrderActionType.APPROVED);

                    List<String> permissionLst = new ArrayList<>();

                    permissionLst.add("stocktaking.service.order.garage.actions.btn.progress");

                    ServiceOrderNotificationThread notificationThread
                            = new ServiceOrderNotificationThread(notification, permissionLst, getLoggedUser().getId()
                            );

                    notificationThread.start();
                } else {
                    showMessage(FacesMessage.SEVERITY_ERROR,
                            getBundlePropertyFile().getString("manager.service.order"),
                            getBundlePropertyFile().getString("manager.authorize.service.order.exception.desc"));
                }
            } else {
                logger.error("Status " + getSelectedServiceOrder().getServiceOrderType());
                showMessage(FacesMessage.SEVERITY_INFO,
                        getBundlePropertyFile().getString("manager.service.order"),
                        getBundlePropertyFile().getString("manager.authorize.service.order"));
            }
            setDetails(null);
        } catch (Exception e) {
            logger.error("authorizeServiceOrder", e);
            showMessage(FacesMessage.SEVERITY_FATAL,
                    getBundlePropertyFile().getString("manager.service.order"),
                    getBundlePropertyFile().getString("manager.authorize.service.order.exception.desc"));
        }
    }

    public void searchServiceOrder() {
        logger.info("searchServiceOrder");
        try {
            Calendar start = Calendar.getInstance();
            Calendar end = Calendar.getInstance();

            start.setTime(getStartDate());
            start.set(Calendar.HOUR_OF_DAY, 0);
            start.set(Calendar.MINUTE, 0);
            start.set(Calendar.SECOND, 0);

            end.setTime(null == getEndDate() ? getToday() : getEndDate());
            end.set(Calendar.HOUR_OF_DAY, 23);
            end.set(Calendar.MINUTE, 59);
            end.set(Calendar.SECOND, 59);

            setServiceOrders(getController().getAllServiceOrderActiveAndStatusIn(Arrays.asList(getSelectedTypes()), 
                    start.getTime(), end.getTime(), new Location(getLocationId())));
        } catch (Exception e) {
            logger.error("searchServiceOrder", e);
            showMessage(FacesMessage.SEVERITY_ERROR,
                    getBundlePropertyFile().getString("manager.search.title"),
                    getBundlePropertyFile().getString("manager.search.exception.desc"));
        }
    }

    /**
     *
     *
     * @param id
     * @return
     */
    public List<ServiceOrderHasProduct> getDetails(String id) {
        logger.info("getDetails");
        try {
            setDetails(getController().findAllProductByOrderId(id));

            logger.info("details loaded size " + details.size());
        } catch (Exception e) {
            logger.error("getDetails", e);
        }
        return null == details ? new ArrayList<>() : details;
    }

    private void loadServiceOrderList() {
        try {
            setServiceOrders(getController().getAllServiceOrderActiveAndPending());
        } catch (Exception e) {
            logger.error("loadServiceOrderList", e);

            setServiceOrders(new ArrayList<>());
            showMessage(FacesMessage.SEVERITY_WARN,
                    getBundlePropertyFile().getString("manager.title"),
                    getBundlePropertyFile().getString("generic.loading.service.orders.list.warning.desc"));
        }
    }

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

    private ServiceOrderController controller;
    private ServiceOrderSingletonController singletonController;
    private GenericValidationController genericController;
    private LocationController locationController;
    private ExpenseController expenseController;
    private TaxiController taxiController;
    private List<ServiceOrderType> types;
    private List<Location> locations;
    private String locationId;
    private ServiceOrderType[] selectedTypes;
    private Date startDate;
    private Date endDate;
    private List<ServiceOrder> serviceOrders;
    private List<ServiceOrderHasProduct> details;
    private ServiceOrder selectedServiceOrder;
    private final ServiceOrderType pending = ServiceOrderType.PENDING;
    private final ServiceOrderType paseTaller = ServiceOrderType.PASE_TALLER;
    private final ServiceOrderType finish = ServiceOrderType.FINISHED;

    @PostConstruct
    public void init() {
        logger.info("init");
        try {
            loadBundlePropertyFile();
            setController(new ServiceOrderController());
            setSingletonController(ServiceOrderSingletonController.getInstance());
            setGenericController(new GenericValidationController());
            setLocationController(new LocationController());
            setExpenseController(new ExpenseController());
            setTaxiController(new TaxiController());
            setServiceOrders(getController().getAllServiceOrderActiveAndPendingByLocation(getLoggedUser().getLocation()));
            setLocations(getLocationController().fillLocationDatatable());
            setLocationId(getLoggedUser().getLocation().getId());
        } catch (Exception e) {
            logger.info("init", e);
        }
    }

    public GenericValidationController getGenericController() {
        return genericController;
    }

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

    public ServiceOrderType getPaseTaller() {
        return paseTaller;
    }

    public ServiceOrderController getController() {
        return controller;
    }

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

    public ServiceOrderSingletonController getSingletonController() {
        return singletonController;
    }

    public void setSingletonController(ServiceOrderSingletonController singletonController) {
        this.singletonController = singletonController;
    }

    public List<ServiceOrderType> getTypes() {
        if (null == types) {
            types = Arrays.asList(ServiceOrderType.values());
        }
        return types;
    }

    public void setTypes(List<ServiceOrderType> types) {
        this.types = types;
    }

    public ServiceOrderType[] getSelectedTypes() {
        return selectedTypes;
    }

    public void setSelectedTypes(ServiceOrderType[] selectedTypes) {
        this.selectedTypes = selectedTypes;
    }

    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 List<ServiceOrder> getServiceOrders() {
        return serviceOrders;
    }

    public void setServiceOrders(List<ServiceOrder> serviceOrders) {
        this.serviceOrders = serviceOrders;
    }

    public List<ServiceOrderHasProduct> getDetails() {
        return details;
    }

    public void setDetails(List<ServiceOrderHasProduct> details) {
        this.details = details;
    }

    public ServiceOrder getSelectedServiceOrder() {
        return selectedServiceOrder;
    }

    public void setSelectedServiceOrder(ServiceOrder selectedServiceOrder) {
        this.selectedServiceOrder = selectedServiceOrder;
    }

    public ServiceOrderType getPending() {
        return pending;
    }

    public List<Location> getLocations() {
        return locations;
    }

    public void setLocations(List<Location> locations) {
        this.locations = locations;
    }

    public String getLocationId() {
        return locationId;
    }

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

    public LocationController getLocationController() {
        return locationController;
    }

    public void setLocationController(LocationController locationController) {
        this.locationController = locationController;
    }

    public ServiceOrderType getFinish() {
        return finish;
    }

    public ExpenseController getExpenseController() {
        return expenseController;
    }

    public void setExpenseController(ExpenseController expenseController) {
        this.expenseController = expenseController;
    }

    public TaxiController getTaxiController() {
        return taxiController;
    }

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

    
    
}
