package de.thpeetz.kontor.comics.views;

import java.util.List;

import lombok.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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.combobox.ComboBox;
import com.vaadin.flow.component.formlayout.FormLayout;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
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.comics.data.Comic;
import de.thpeetz.kontor.comics.data.ComicWork;
import de.thpeetz.kontor.comics.data.Publisher;

public class ComicForm extends FormLayout {

    private static final Logger log = LoggerFactory.getLogger(ComicForm.class);

    TextField title = new TextField("Title");
    ComboBox<Publisher> publisher = new ComboBox<>("Publisher");
    TextField weblink = new TextField("Link");
    Checkbox currentOrder = new Checkbox("Current order");
    Checkbox completed = new Checkbox("Completed");
    Grid<ComicWork> comicWorks = new Grid<>(ComicWork.class);

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

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

    public ComicForm(List<Publisher> publishers) {
        addClassName("comic-form");
        binder.bindInstanceFields(this);

        publisher.setItems(publishers);
        publisher.setItemLabelGenerator(Publisher::getName);
        // comicWorks.addClassName("comic-works-grid");
        // comicWorks.setSizeFull();
        comicWorks.setColumns("workType.name", "artist.name");
        comicWorks.getColumnByKey("workType.name").setHeader("Work type");
        comicWorks.getColumnByKey("artist.name").setHeader("Artist");
        comicWorks.getColumns().forEach(col -> col.setAutoWidth(true));
        add(title, publisher, weblink, currentOrder, completed, comicWorks, 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 DeleteEvent(this, binder.getBean())));
        close.addClickListener(event -> fireEvent(new CloseEvent(this)));

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

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

    public void setComic(Comic comic) {
        binder.setBean(comic);
    }

    public void setComicWorks(List<ComicWork> works) {
        log.info("Setting comic works: {}", works);
        comicWorks.setItems(works);
    }

    @Getter
    public abstract static class ComicFormEvent extends ComponentEvent<ComicForm> {
        private final Comic comic;

        protected ComicFormEvent(ComicForm source, Comic comic) {
            super(source, false);
            this.comic = comic;
        }

    }

    public static class SaveEvent extends ComicFormEvent {
        SaveEvent(ComicForm source, Comic comic) {
            super(source, comic);
        }
    }

    public static class DeleteEvent extends ComicFormEvent {
        DeleteEvent(ComicForm source, Comic comic) {
            super(source, comic);
        }
    }

    public static class CloseEvent extends ComicFormEvent {
        CloseEvent(ComicForm source) {
            super(source, null);
        }
    }

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

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

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