package eu.dnetlib.client.adminpanel;

import com.github.gwtbootstrap.client.ui.*;
import com.github.gwtbootstrap.client.ui.Button;
import com.github.gwtbootstrap.client.ui.SubmitButton;
import com.github.gwtbootstrap.client.ui.TextBox;
import com.github.gwtbootstrap.client.ui.constants.AlertType;
import com.github.gwtbootstrap.client.ui.constants.BackdropType;
import com.github.gwtbootstrap.client.ui.constants.ButtonType;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.InputElement;
import com.google.gwt.dom.client.NodeList;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.query.client.Function;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.*;
import com.google.gwt.user.client.ui.Label;
import eu.dnetlib.client.Admin;
import eu.dnetlib.client.AdminWidget;
import eu.dnetlib.espas.gui.client.UserService;
import eu.dnetlib.espas.gui.client.UserServiceAsync;
import eu.dnetlib.espas.gui.shared.User;

import java.util.ArrayList;
import java.util.List;

import static com.google.gwt.query.client.GQuery.$;

public class ManageUsersWidget implements AdminWidget {
	
	private static ManageUsersWidget instance = null;

    private FlowPanel manageUsersPanel = new FlowPanel();

    private Alert errorAlert = new Alert();
    private Alert successAlert = new Alert();
    private Alert warningAlert = new Alert();

    private FlowPanel pageControlsPanel = new FlowPanel();
    private FlowPanel usersPanel = new FlowPanel();

    private TextBox search = new TextBox();
	
	private UserServiceAsync userAccessService = GWT.create(UserService.class);
	
    private List<User> users = new ArrayList<User>();
    private List<User> activeUsers = new ArrayList<User>();
    private List<User> inactiveUsers = new ArrayList<User>();

    private List<User> allMatchingUsers = new ArrayList<User>();
    private List<User> activeMatchingUsers = new ArrayList<User>();
    private List<User> inactiveMatchingUsers = new ArrayList<User>();
	
	private ManageUsersWidget() {

        manageUsersPanel.addStyleName("contentPanel");

        errorAlert.setType(AlertType.ERROR);
        errorAlert.setVisible(false);
        errorAlert.setClose(false);
        manageUsersPanel.add(errorAlert);

        successAlert.setType(AlertType.SUCCESS);
        successAlert.setVisible(false);
        successAlert.setClose(false);
        manageUsersPanel.add(successAlert);

        warningAlert.setType(AlertType.WARNING);
        warningAlert.setVisible(false);
        warningAlert.setClose(false);
        manageUsersPanel.add(warningAlert);

        manageUsersPanel.add(pageControlsPanel);
        manageUsersPanel.add(usersPanel);

        pageControlsPanel.addStyleName("row");
        pageControlsPanel.addStyleName("page-controls");
	}
	
	public static final ManageUsersWidget getInstance() {
		
		if(instance==null)
			instance = new ManageUsersWidget();
		
		return instance;
	}

    @Override
    public void clear() {

        errorAlert.setVisible(false);
        successAlert.setVisible(false);
        warningAlert.setVisible(false);

        usersPanel.clear();
        pageControlsPanel.clear();

        search.setValue("");
    }

    @Override
    public void reload() {

        Admin.menuBar.clear();

        Admin.menuBar.add(new HTML("<div class=\"sidebar-toggler visible-xs\"><i class=\"ion-navicon\"></i></div>"));
        Admin.menuBar.add(new HTML("<div class=\"page-title\" id=\"pageTitle\">Users</div>"));

        Form searchForm = new Form();
        searchForm.addStyleName("search");

        search.setPlaceholder("Search users (name, email)...");
        searchForm.add(search);

        SubmitButton submitSearchButton = new SubmitButton();
        searchForm.add(submitSearchButton);

        searchForm.addSubmitHandler(new Form.SubmitHandler() {
            @Override
            public void onSubmit(Form.SubmitEvent event) {

                errorAlert.setVisible(false);
                successAlert.setVisible(false);
                warningAlert.setVisible(false);

                ManageUsersWidget.getInstance().allMatchingUsers.clear();
                ManageUsersWidget.getInstance().activeMatchingUsers.clear();
                ManageUsersWidget.getInstance().inactiveMatchingUsers.clear();

                if(search.getValue()!=null && !search.getValue().trim().equals("")) {

                    for(User user : users) {

                        if(user.getName().toLowerCase().contains(search.getValue().trim().toLowerCase())
                                || user.getEmail().toLowerCase().contains(search.getValue().trim().toLowerCase())) {
                            allMatchingUsers.add(user);

                            if(user.isActivated()) {
                                activeMatchingUsers.add(user);
                            } else {
                                inactiveMatchingUsers.add(user);
                            }
                        }
                    }

                } else {
                    allMatchingUsers.addAll(users);
                    activeMatchingUsers.addAll(activeUsers);
                    inactiveMatchingUsers.addAll(inactiveUsers);
                }

                updateContents(allMatchingUsers);
                updateControls();
            }
        });

        Admin.menuBar.add(searchForm);

        updateUsers(true, null);
    }

    private void updateUsers(final boolean clearAlerts, final String successMessage) {

        final HTML loadingWheel = new HTML("<div class=\"loader-big\"></div><div class=\"whiteFilm\"></div>");
        manageUsersPanel.addStyleName("loading-big");
        manageUsersPanel.add(loadingWheel);

        userAccessService.getUsers(new AsyncCallback<List<User>>() {

            @Override
            public void onSuccess(List<User> users) {

                if(clearAlerts) {
                    errorAlert.setVisible(false);
                    successAlert.setVisible(false);
                    warningAlert.setVisible(false);
                }

                if(successMessage!=null) {
                    successAlert.setText(successMessage);
                    successAlert.setVisible(true);
                }

                manageUsersPanel.removeStyleName("loading-big");
                manageUsersPanel.remove(loadingWheel);

                ManageUsersWidget.getInstance().users.clear();
                ManageUsersWidget.getInstance().users.addAll(users);

                ManageUsersWidget.getInstance().allMatchingUsers.clear();

                ManageUsersWidget.getInstance().activeUsers.clear();
                ManageUsersWidget.getInstance().inactiveUsers.clear();

                ManageUsersWidget.getInstance().activeMatchingUsers.clear();
                ManageUsersWidget.getInstance().inactiveMatchingUsers.clear();

                for(User user : users){
                    if(user.isActivated()) {
                        activeUsers.add(user);
                    } else {
                        inactiveUsers.add(user);
                    }
                }

                if(search.getValue()!=null && !search.getValue().trim().equals("")) {

                    for(User user : users) {

                        if(user.getName().toLowerCase().contains(search.getValue().trim().toLowerCase())
                                || user.getEmail().toLowerCase().contains(search.getValue().trim().toLowerCase())) {
                            allMatchingUsers.add(user);

                            if(user.isActivated()) {
                                activeMatchingUsers.add(user);
                            } else {
                                inactiveMatchingUsers.add(user);
                            }
                        }
                    }

                } else {
                    allMatchingUsers.addAll(users);
                    activeMatchingUsers.addAll(activeUsers);
                    inactiveMatchingUsers.addAll(inactiveUsers);
                }

                updateControls();
                updateContents(allMatchingUsers);
            }

            @Override
            public void onFailure(Throwable arg0) {

                manageUsersPanel.removeStyleName("loading-big");
                manageUsersPanel.remove(loadingWheel);

                successAlert.setVisible(false);
                warningAlert.setVisible(false);

                errorAlert.setText("System error retrieving users");
                errorAlert.setVisible(true);
            }
        });
    }

    @Override
    public void setToken(String token) {

    }

    @Override
    public void afterAdditionToRootPanel() {

    }

    public void updateControls() {

        pageControlsPanel.clear();

        FlowPanel filters = new FlowPanel();
        filters.addStyleName("col-md-12");
        filters.addStyleName("filters");

        pageControlsPanel.add(filters);

        FlowPanel links = new FlowPanel();
        links.addStyleName("links");

        filters.add(links);

        Label filterLabel = new Label("Filter users:");
        filterLabel.addStyleName("filterLabel");
        links.add(filterLabel);

        final Anchor allUsersLink = new Anchor("All Users (" + allMatchingUsers.size() + ")");
        allUsersLink.addStyleName("active");
        links.add(allUsersLink);

        final Anchor activeUsersLink = new Anchor("Active (" + activeMatchingUsers.size() + ")");
        links.add(activeUsersLink);

        final Anchor inactiveUsersLink = new Anchor("Inactive (" + inactiveMatchingUsers.size() + ")");
        links.add(inactiveUsersLink);

        allUsersLink.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {

                allUsersLink.addStyleName("active");
                activeUsersLink.removeStyleName("active");
                inactiveUsersLink.removeStyleName("active");
                updateContents(allMatchingUsers);
            }
        });

        activeUsersLink.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {

                allUsersLink.removeStyleName("active");
                activeUsersLink.addStyleName("active");
                inactiveUsersLink.removeStyleName("active");
                updateContents(activeMatchingUsers);
            }
        });

        inactiveUsersLink.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {

                allUsersLink.removeStyleName("active");
                activeUsersLink.removeStyleName("active");
                inactiveUsersLink.addStyleName("active");
                updateContents(inactiveMatchingUsers);
            }
        });


        FlowPanel actions = new FlowPanel();
        actions.addStyleName("show-options");

        filters.add(actions);

        DropdownButton bulkActions = new DropdownButton();
        bulkActions.setText("Bulk Actions");
        bulkActions.setType(ButtonType.DEFAULT);

        NavLink activateButton = new NavLink("Activate");
        activateButton.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {

                errorAlert.setVisible(false);
                successAlert.setVisible(false);
                warningAlert.setVisible(false);

                List<String> emails = getCheckedUsers();

                if(!emails.isEmpty()) {
                    activate(emails);
                } else {
                    warningAlert.setText("You haven't selected any users");
                    warningAlert.setVisible(true);
                }
            }
        });
        bulkActions.add(activateButton);

        NavLink deactivateButton = new NavLink("Deactivate");
        deactivateButton.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {

                errorAlert.setVisible(false);
                successAlert.setVisible(false);
                warningAlert.setVisible(false);

                List<String> emails = getCheckedUsers();

                if(!emails.isEmpty()) {
                    deactivate(emails);
                } else {
                    warningAlert.setText("You haven't selected any users");
                    warningAlert.setVisible(true);
                }
            }
        });
        bulkActions.add(deactivateButton);

        NavLink deleteButton = new NavLink("Delete");
        deleteButton.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {

                errorAlert.setVisible(false);
                successAlert.setVisible(false);
                warningAlert.setVisible(false);

                List<String> emails = getCheckedUsers();

                if(!emails.isEmpty()) {
                    delete(emails);
                } else {
                    warningAlert.setText("You haven't selected any users");
                    warningAlert.setVisible(true);
                }
            }
        });
        bulkActions.add(deleteButton);

        actions.add(bulkActions);
    }

	public void updateContents(List<User> users) {

        usersPanel.clear();

        String contents = "<div class=\"row users-list\">";
        contents += "<div class=\"col-md-12\">";

        contents += "<div class=\"row headers\">" +
                "<div class=\"col-sm-1 header select-users\">" +
                "<input id=\"allUsersCheckbox\" type=\"checkbox\">" +
                "</div>" +
                "<div class=\"col-sm-3 header hidden-xs\">" +
                "<label><a href=\"#\">Name</a></label>" +
                "</div>" +
                "<div class=\"col-sm-4 header hidden-xs\">" +
                "<label><a href=\"#\">Email</a></label>" +
                "</div>" +
                "<div class=\"col-sm-2 header hidden-xs\">" +
                "<label><a href=\"#\">Country</a></label>" +
                "</div>" +
                "<div class=\"col-sm-1 header hidden-xs\">" +
                "<label><a href=\"#\">Activated</a></label>" +
                "</div>" +
                "<div class=\"col-sm-1 header hidden-xs\">" +
                "<label><a href=\"#\">Delete</a></label>" +
                "</div>" +
                "</div>";

        if(users.size()==0) {

            contents += "<div class=\"row user\">" +
                    "<div class=\"col-md-12\"><div class=\"alert alert-warning\">No users found</div></div>" +
                    "</div>";

        } else {
            for (User user : users) {

                contents += "<div class=\"row user\">" +
                        "<div class=\"col-sm-1 avatar\"><input id=\"" + user.getEmail() + "#checkBox\" class=\"checkBox\" type=\"checkbox\" name=\"select-user\"></div>" +
                        "<div class=\"col-sm-3\"><a class=\"name\" href=\"#\">" + user.getName() + "</a></div>" +
                        "<div class=\"col-sm-4\"><div class=\"email\" href=\"#\">" + user.getEmail() + "</div></div>" +
                        "<div class=\"col-sm-2\"><div class=\"country\" href=\"#\">" + user.getCountry() + "</div></div>";

                if (user.isActivated()) {
                    contents += "<div class=\"col-sm-1\"><div class=\"activated\" href=\"#\"><input id=\"" + user.getEmail() +
                            "#deactivate\" class=\"deactivate\" type=\"image\" src=\"imgs/check-icon.png\" width=20 height=20 " +
                            "title=\"Deactivate\"></div></div>";
                } else {
                    contents += "<div class=\"col-sm-1\"><div class=\"activated\" href=\"#\"><input id=\"" + user.getEmail() +
                            "#activate\" class=\"activate\" type=\"image\" src=\"imgs/x-icon.png\" width=20 height=20 " +
                            "title=\"Activate\"></div></div>";
                }

                contents += "<div class=\"col-sm-1\"><div class=\"deleteUser\" href=\"#\">" +
                        "<input id=\"" + user.getEmail() + "#delete\" class=\"delete\" type=\"image\" src=\"imgs/icn_trash.png\" " +
                        "width=25 height=20 title=\"Delete\"></div></div>" +
                        "</div>";
            }
        }

        contents += "</div>";
        contents += "</div>";

        HTML usersList = new HTML();
        usersList.setHTML(contents);

        usersPanel.add(usersList);

        addWidgetHandlers();
    }

	@Override
	public Widget asWidget() {
		return manageUsersPanel;
	}
	
	public void addWidgetHandlers() {
		
		$("#allUsersCheckbox").click(new Function() {
			
			public boolean f(Event e) {

				InputElement allUsers = (InputElement) Document.get().getElementById("allUsersCheckbox");
				
				NodeList<Element> checkBoxes = $(".checkBox").get();
				
				if(allUsers.isChecked()) {
					for(int i=0; i<checkBoxes.getLength(); i++) {
						InputElement checkBox = (InputElement) checkBoxes.getItem(i);
						checkBox.setChecked(true);
					}
				} else {
					for(int i=0; i<checkBoxes.getLength(); i++) {
						InputElement checkBox = (InputElement) checkBoxes.getItem(i);
						checkBox.setChecked(false);
					}
				}
				
				return true;
			}
		});

		$(".delete").click(new Function() {
			
			public boolean f(Event e) {

                errorAlert.setVisible(false);
                successAlert.setVisible(false);
                warningAlert.setVisible(false);

                String[] idParts = $(e).get(0).getId().split("#");
				List<String> emails = new ArrayList<String>();
				emails.add(idParts[0]);
				
				delete(emails);

				return true;
			}
		});
		
		$(".activate").click(new Function() {
			
			public boolean f(Event e) {

                errorAlert.setVisible(false);
                successAlert.setVisible(false);
                warningAlert.setVisible(false);

                String[] idParts = $(e).get(0).getId().split("#");
				List<String> emails = new ArrayList<String>();
				emails.add(idParts[0]);
				
				activate(emails);
				
				return true;
			}
		});

		$(".deactivate").click(new Function() {
			
			public boolean f(Event e) {

                errorAlert.setVisible(false);
                successAlert.setVisible(false);
                warningAlert.setVisible(false);

                String[] idParts = $(e).get(0).getId().split("#");
				List<String> emails = new ArrayList<String>();
				emails.add(idParts[0]);
				
				deactivate(emails);
				
				return true;
			}
		});
	}
	
	private void activate(final List<String> emails) {

        final HTML loadingWheel = new HTML("<div class=\"loader-big\"></div><div class=\"whiteFilm\"></div>");
        manageUsersPanel.addStyleName("loading-big");
        manageUsersPanel.add(loadingWheel);
		
		userAccessService.activateUsers(emails, new AsyncCallback<Void>() {
			
			@Override
			public void onSuccess(Void arg) {

                manageUsersPanel.removeStyleName("loading-big");
                manageUsersPanel.remove(loadingWheel);

				updateUsers(false, "User(s) activated successfully");
			}
			
			@Override
			public void onFailure(Throwable arg0) {

                manageUsersPanel.removeStyleName("loading-big");
                manageUsersPanel.remove(loadingWheel);

                errorAlert.setText("Failed to activate user(s)");
                errorAlert.setVisible(true);
			}
		});
	}
	
	private void deactivate(final List<String> emails) {

        final HTML loadingWheel = new HTML("<div class=\"loader-big\"></div><div class=\"whiteFilm\"></div>");
        manageUsersPanel.addStyleName("loading-big");
        manageUsersPanel.add(loadingWheel);
		
		userAccessService.deactivateUsers(emails, new AsyncCallback<Void>() {
			
			@Override
			public void onSuccess(Void arg) {

                manageUsersPanel.removeStyleName("loading-big");
                manageUsersPanel.remove(loadingWheel);

                updateUsers(false, "User(s) deactivated successfully");
			}
			
			@Override
			public void onFailure(Throwable arg0) {

                manageUsersPanel.removeStyleName("loading-big");
                manageUsersPanel.remove(loadingWheel);

                errorAlert.setText("Failed to deactivate user(s)");
                errorAlert.setVisible(true);
			}
		});
	}
	
	private void delete(final List<String> emails) {

        final Modal deleteConfirmationPopup = new Modal();

        deleteConfirmationPopup.addStyleName("confirmationModal");
        deleteConfirmationPopup.setAnimation(true);
        deleteConfirmationPopup.setBackdrop(BackdropType.STATIC);

        deleteConfirmationPopup.setTitle("Delete Confirmation");

        HTML message = new HTML("Are you sure you want to delete the selected user(s)?");
        deleteConfirmationPopup.add(message);

        FlowPanel actionButtons = new FlowPanel();
        actionButtons.addStyleName("confirmationModalButtons");

        ModalFooter modalFooter = new ModalFooter();
        modalFooter.add(actionButtons);
        deleteConfirmationPopup.add(modalFooter);

        Button no = new Button("Cancel");
        no.setType(ButtonType.DEFAULT);
        no.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                deleteConfirmationPopup.hide();
                deleteConfirmationPopup.removeFromParent();
            }
        });
        actionButtons.add(no);

        Button yes = new Button("Yes, delete them");
        yes.setType(ButtonType.DANGER);
        yes.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {

                deleteConfirmationPopup.hide();
                deleteConfirmationPopup.removeFromParent();

                final HTML loadingWheel = new HTML("<div class=\"loader-big\"></div><div class=\"whiteFilm\"></div>");
                manageUsersPanel.addStyleName("loading-big");
                manageUsersPanel.add(loadingWheel);

                userAccessService.deleteUsers(emails, new AsyncCallback<Void>() {

                    @Override
                    public void onSuccess(Void arg) {

                        manageUsersPanel.removeStyleName("loading-big");
                        manageUsersPanel.remove(loadingWheel);

                        updateUsers(false, "User(s) deleted successfully");
                        AdminPanelController.getInstance().updateNoOfActions();
                    }

                    @Override
                    public void onFailure(Throwable arg0) {

                        manageUsersPanel.removeStyleName("loading-big");
                        manageUsersPanel.remove(loadingWheel);

                        errorAlert.setText("Failed to delete the selected user(s)");
                        errorAlert.setVisible(true);
                    }
                });
            }
        });
        actionButtons.add(yes);

        deleteConfirmationPopup.show();
	}
	
	private List<String> getCheckedUsers() {
		
		List<String> emails = new ArrayList<String>();
		
		NodeList<Element> checkBoxes = $(".checkBox").get();
		for(int i=0; i<checkBoxes.getLength(); i++) {
			InputElement checkBox = (InputElement) checkBoxes.getItem(i);
			if(checkBox.isChecked()) {
				String[] idParts = checkBox.getId().split("#");
				emails.add(idParts[0]);
			}
		}
		
		return emails;
	}
}
