package eu.dnetlib.client.adminpanel;

import com.github.gwtbootstrap.client.ui.*;
import com.github.gwtbootstrap.client.ui.SubmitButton;
import com.github.gwtbootstrap.client.ui.TextBox;
import com.github.gwtbootstrap.client.ui.constants.AlertType;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.InputElement;
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 ManageRolesWidget implements AdminWidget {
	
	private static ManageRolesWidget instance = null;

    private FlowPanel manageUserRolesPanel = 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> dataProviders = new ArrayList<User>();
    private List<User> pendingDataProviders = new ArrayList<User>();
    private List<User> admins = new ArrayList<User>();

    private List<User> allMatchingUsers = new ArrayList<User>();
    private List<User> matchingDataProviders = new ArrayList<User>();
    private List<User> matchingPendingDataProviders = new ArrayList<User>();
    private List<User> matchingAdmins = new ArrayList<User>();
	
	private ManageRolesWidget() {

        manageUserRolesPanel.addStyleName("contentPanel");

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

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

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

        manageUserRolesPanel.add(pageControlsPanel);
        manageUserRolesPanel.add(usersPanel);

        pageControlsPanel.addStyleName("row");
        pageControlsPanel.addStyleName("page-controls");
	}
	
	public static final ManageRolesWidget getInstance() {
		
		if(instance==null)
			instance = new ManageRolesWidget();
		
		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\">User Roles</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);

                ManageRolesWidget.getInstance().allMatchingUsers.clear();
                ManageRolesWidget.getInstance().matchingDataProviders.clear();
                ManageRolesWidget.getInstance().matchingPendingDataProviders.clear();
                ManageRolesWidget.getInstance().matchingAdmins.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);

                            for(String role : user.getRoles()) {
                                if(role.equals("dataprovider"))
                                    matchingDataProviders.add(user);
                                if(role.equals("admin"))
                                    matchingAdmins.add(user);
                            }

                            if(user.isPendingDataProvider())
                                matchingPendingDataProviders.add(user);
                        }
                    }

                } else {
                    allMatchingUsers.addAll(users);
                    matchingDataProviders.addAll(dataProviders);
                    matchingPendingDataProviders.addAll(pendingDataProviders);
                    matchingAdmins.addAll(admins);
                }

                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>");
        manageUserRolesPanel.addStyleName("loading-big");
        manageUserRolesPanel.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);
                }

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

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

                ManageRolesWidget.getInstance().allMatchingUsers.clear();

                ManageRolesWidget.getInstance().dataProviders.clear();
                ManageRolesWidget.getInstance().pendingDataProviders.clear();
                ManageRolesWidget.getInstance().admins.clear();

                ManageRolesWidget.getInstance().matchingDataProviders.clear();
                ManageRolesWidget.getInstance().matchingPendingDataProviders.clear();
                ManageRolesWidget.getInstance().matchingAdmins.clear();

                for(User user : users) {

                    for(String role : user.getRoles()) {
                        if(role.equals("dataprovider"))
                            dataProviders.add(user);
                        if(role.equals("admin"))
                            admins.add(user);
                    }

                    if(user.isPendingDataProvider())
                        pendingDataProviders.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);

                            for(String role : user.getRoles()) {
                                if(role.equals("dataprovider"))
                                    matchingDataProviders.add(user);
                                if(role.equals("admin"))
                                    matchingAdmins.add(user);
                            }

                            if(user.isPendingDataProvider())
                                matchingPendingDataProviders.add(user);
                        }
                    }

                } else {
                    allMatchingUsers.addAll(users);
                    matchingDataProviders.addAll(dataProviders);
                    matchingPendingDataProviders.addAll(pendingDataProviders);
                    matchingAdmins.addAll(admins);
                }

                updateControls();
                updateContents(allMatchingUsers);
            }

            @Override
            public void onFailure(Throwable arg0) {

                manageUserRolesPanel.removeStyleName("loading-big");
                manageUserRolesPanel.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 dataProvidersLink = new Anchor("Data Providers (" + matchingDataProviders.size() + ")");
        links.add(dataProvidersLink);

        final Anchor pendingDataProvidersLink = new Anchor("Pending Data Providers (" + matchingPendingDataProviders.size() + ")");
        links.add(pendingDataProvidersLink);

        final Anchor administratorsLink = new Anchor("Administrators (" + matchingAdmins.size() + ")");
        links.add(administratorsLink);

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

                allUsersLink.addStyleName("active");
                dataProvidersLink.removeStyleName("active");
                pendingDataProvidersLink.removeStyleName("active");
                administratorsLink.removeStyleName("active");
                updateContents(allMatchingUsers);
            }
        });

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

                allUsersLink.removeStyleName("active");
                dataProvidersLink.addStyleName("active");
                pendingDataProvidersLink.removeStyleName("active");
                administratorsLink.removeStyleName("active");
                updateContents(matchingDataProviders);
            }
        });

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

                allUsersLink.removeStyleName("active");
                dataProvidersLink.removeStyleName("active");
                pendingDataProvidersLink.addStyleName("active");
                administratorsLink.removeStyleName("active");
                updateContents(matchingPendingDataProviders);
            }
        });

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

                allUsersLink.removeStyleName("active");
                dataProvidersLink.removeStyleName("active");
                pendingDataProvidersLink.removeStyleName("active");
                administratorsLink.addStyleName("active");
                updateContents(matchingAdmins);
            }
        });
    }
	
	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-4 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=\"#\">Data Provider</a></label>" +
                "</div>" +
                "<div class=\"col-sm-2 header hidden-xs\">" +
                "<label><a href=\"#\">Administrator</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-4\"><a class=\"name\" href=\"#\">" + user.getName() + "</a></div>" +
                        "<div class=\"col-sm-4\"><div class=\"email\" href=\"#\">" + user.getEmail() + "</div></div>";

                if(user.getRoles().contains("dataprovider"))
                    contents += "<div class=\"col-sm-2\"><input id=\"" + user.getEmail() + "#dataprovider\" class=\"checkBox\" type=\"checkbox\" checked></div>";
                else {
                    if(user.isPendingDataProvider())
                        contents += "<div class=\"col-sm-2\"><input id=\"" + user.getEmail() + "#dataprovider\" class=\"checkBox\" type=\"checkbox\"><span class=\"label label-warning\">Pending</span></div>";
                    else
                        contents += "<div class=\"col-sm-2\"><input id=\"" + user.getEmail() + "#dataprovider\" class=\"checkBox\" type=\"checkbox\"></div>";
                }

                if(user.getRoles().contains("admin"))
                    contents += "<div class=\"col-sm-2\"><input id=\"" + user.getEmail() + "#admin\" class=\"checkBox\" type=\"checkbox\" checked></div>";
                else
                    contents += "<div class=\"col-sm-2\"><input id=\"" + user.getEmail() + "#admin\" class=\"checkBox\" type=\"checkbox\"></div>";

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

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

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

        usersPanel.add(usersList);

        addWidgetHandlers();
	}

	@Override
	public Widget asWidget() {
		return manageUserRolesPanel;
	}
	
	public void addWidgetHandlers() {
		
		$(".checkBox").click(new Function() {

			public boolean f(Event e) {

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

                String[] idParts = $(e).get(0).getId().split("#");

				InputElement checkbox = (InputElement) Document.get().getElementById($(e).get(0).getId());

				if(checkbox.isChecked()) {

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

					userAccessService.addRoleToUser(idParts[0], idParts[1], new AsyncCallback<Void>() {

						@Override
						public void onFailure(Throwable arg0) {

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

                            errorAlert.setText("Failed to add user role");
                            errorAlert.setVisible(true);
						}

						@Override
						public void onSuccess(Void arg0) {

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

                            updateUsers(false, "User role added successfully");

							AdminPanelController.getInstance().updateNoOfActions();
                            Admin.updateDataProviderAdministrators();
						}
					});
				} else {

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

					userAccessService.removeRoleFromUser(idParts[0], idParts[1], new AsyncCallback<Void>() {

						@Override
						public void onFailure(Throwable arg0) {
                            manageUserRolesPanel.removeStyleName("loading-big");
                            manageUserRolesPanel.remove(loadingWheel);

                            errorAlert.setText("Failed to remove user role");
                            errorAlert.setVisible(true);
						}

						@Override
						public void onSuccess(Void arg0) {

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

                            updateUsers(false, "User role removed successfully");
                            Admin.updateDataProviderAdministrators();
						}
					});
				}

				return true;
			}
		});
	}
}
