package de.thpeetz.kontor.media.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.combobox.ComboBox;
import com.vaadin.flow.component.formlayout.FormLayout;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.data.binder.BeanValidationBinder;
import com.vaadin.flow.data.binder.Binder;
import de.thpeetz.kontor.media.data.MediaActor;
import de.thpeetz.kontor.media.data.MediaActorFile;
import de.thpeetz.kontor.media.data.MediaFile;
import lombok.Getter;

import java.util.List;

public class MediaActorFileForm extends FormLayout {
    ComboBox<MediaFile> mediaFile = new ComboBox<>("Media File");
    ComboBox<MediaActor> mediaActor = new ComboBox<>("Actor");

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

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

    public MediaActorFileForm(List<MediaFile> mediaFiles, List<MediaActor> actors) {
        addClassName("mediaactorfile-form");
        binder.bindInstanceFields(this);

        mediaFile.setItems(mediaFiles);
        mediaFile.setItemLabelGenerator(MediaFile::getTitle);
        mediaActor.setItems(actors);
        mediaActor.setItemLabelGenerator(MediaActor::getName);
        add(mediaFile, mediaActor, createButtonsLayout());
    }

    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 MediaActorFileForm.DeleteEvent(this, binder.getBean())));
        close.addClickListener(event -> fireEvent(new MediaActorFileForm.CloseEvent(this)));

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

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

    public void setMediaActorFile(MediaActorFile mediaActorFile) {
        binder.setBean(mediaActorFile);
    }

    public abstract static class MediaActorFileFormEvent extends ComponentEvent<MediaActorFileForm> {
        @Getter
        private MediaActorFile mediaActorFile;

        protected MediaActorFileFormEvent(MediaActorFileForm source, MediaActorFile mediaActorFile) {
            super(source, false);
            this.mediaActorFile = mediaActorFile;
        }
    }

    public static class SaveEvent extends MediaActorFileForm.MediaActorFileFormEvent {
        SaveEvent(MediaActorFileForm source, MediaActorFile mediaActorFile) {
            super(source, mediaActorFile);
        }
    }

    public static class DeleteEvent extends MediaActorFileForm.MediaActorFileFormEvent {
        DeleteEvent(MediaActorFileForm source, MediaActorFile mediaActorFile) {
            super(source, mediaActorFile);
        }
    }

    public static class CloseEvent extends MediaActorFileForm.MediaActorFileFormEvent {
        CloseEvent(MediaActorFileForm source) {
            super(source, null);
        }
    }

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

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

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