package de.thpeetz.kontor.admin.views;

import com.vaadin.flow.component.ComponentEvent;
import com.vaadin.flow.component.ComponentEventListener;
import com.vaadin.flow.component.Key;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.checkbox.Checkbox;
import com.vaadin.flow.component.checkbox.CheckboxGroup;
import com.vaadin.flow.component.checkbox.CheckboxGroupVariant;
import com.vaadin.flow.component.formlayout.FormLayout;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.textfield.EmailField;
import com.vaadin.flow.component.textfield.PasswordField;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.data.binder.BeanValidationBinder;
import com.vaadin.flow.data.binder.Binder;
import de.thpeetz.kontor.admin.data.Permission;
import de.thpeetz.kontor.admin.data.Profile;
import lombok.extern.slf4j.Slf4j;

import java.util.List;

@Slf4j
public class ProfileForm extends FormLayout {

    TextField userName = new TextField("User name");
    PasswordField password = new PasswordField("Password");
    EmailField email = new EmailField("Email");
    TextField firstName = new TextField("First name");
    TextField lastName = new TextField("Last name");
    Checkbox enabled = new Checkbox("Enabled");
    String originalPassword;

    CheckboxGroup<Permission> permissionList = new CheckboxGroup<>("Permissions");

    Button save = new Button("Save");
    Button delete = new Button("Delete");
    Button close = new Button("Cancel");

    Binder<Profile> binder = new BeanValidationBinder<>(Profile.class);

    public ProfileForm() {
        addClassName("profile-form");
        binder.bindInstanceFields(this);
        add(userName, password, email, firstName, lastName, enabled, configurePermissionsGroup(), createButtonsLayout());
    }

    private CheckboxGroup<Permission> configurePermissionsGroup() {
        permissionList.addThemeVariants(CheckboxGroupVariant.LUMO_VERTICAL);
        permissionList.setItemLabelGenerator(Permission::getName);
        permissionList.addValueChangeListener(event -> {
            log.debug("permissions changed: {}", event);
        });
        return permissionList;
    }

    private HorizontalLayout createButtonsLayout() {
        save.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        delete.addThemeVariants(ButtonVariant.LUMO_ERROR);
        close.addThemeVariants(ButtonVariant.LUMO_TERTIARY);

        save.addClickShortcut(Key.ENTER);
        close.addClickShortcut(Key.ESCAPE);

        save.addClickListener(event -> validateAndSave());
        delete.addClickListener(event -> fireEvent(new ProfileForm.DeleteEvent(this, binder.getBean())));
        close.addClickListener(event -> fireEvent(new ProfileForm.CloseEvent(this)));

        binder.addStatusChangeListener(e -> save.setEnabled(binder.isValid()));
        return new HorizontalLayout(save, delete, close);
    }

    private void validateAndSave() {
        if (binder.isValid()) {
            fireEvent(new ProfileForm.SaveEvent(this, binder.getBean()));
        }
    }

    public void setProfile(Profile profile) {
        binder.setBean(profile);
        //log.debug("UserForm.setUser: {}", user);
        if (profile != null) {
            this.originalPassword = profile.getPassword();
        } else {
            this.originalPassword = null;
        }
    }

    public void setPermissions(List<Permission> permissions, Profile profile) {
        permissionList.setItems(permissions);
        profile.getAssignments().stream().forEach(assignment -> {
            permissionList.select(assignment.getPermission());
        });
    }

    public boolean hasPasswordChanged(Profile profile) {
        return !originalPassword.equals(profile.getPassword());
    }

    public abstract static class ProfileFormEvent extends ComponentEvent<ProfileForm> {
        private Profile profile;

        protected ProfileFormEvent(ProfileForm source, Profile profile) {
            super(source, false);
            this.profile = profile;
        }

        public Profile getProfile() {
            return profile;
        }
    }

    public static class SaveEvent extends ProfileForm.ProfileFormEvent {
        SaveEvent(ProfileForm source, Profile profile) {
            super(source, profile);
        }
    }

    public static class DeleteEvent extends ProfileForm.ProfileFormEvent {
        DeleteEvent(ProfileForm source, Profile profile) {
            super(source, profile);
        }
    }

    public static class CloseEvent extends ProfileForm.ProfileFormEvent {
        CloseEvent(ProfileForm source) {
            super(source, null);
        }
    }

    public void addDeleteListener(ComponentEventListener<ProfileForm.DeleteEvent> listener) {
        addListener(ProfileForm.DeleteEvent.class, listener);
    }

    public void addSaveListener(ComponentEventListener<ProfileForm.SaveEvent> listener) {
        addListener(ProfileForm.SaveEvent.class, listener);
    }

    public void addCloseListener(ComponentEventListener<ProfileForm.CloseEvent> listener) {
        addListener(ProfileForm.CloseEvent.class, listener);
    }
}
