package com.aksenov.monitor.views.manufacturer;

import com.aksenov.monitor.data.Customer;
import com.aksenov.monitor.data.Manufacturer;
import com.aksenov.monitor.services.ManufacturerService;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.formlayout.FormLayout;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.grid.GridVariant;
import com.vaadin.flow.component.grid.HeaderRow;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.notification.Notification.Position;
import com.vaadin.flow.component.notification.NotificationVariant;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.splitlayout.SplitLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.data.binder.BeanValidationBinder;
import com.vaadin.flow.data.binder.ValidationException;
import com.vaadin.flow.data.provider.ListDataProvider;
import com.vaadin.flow.function.SerializablePredicate;
import com.vaadin.flow.router.BeforeEnterEvent;
import com.vaadin.flow.router.BeforeEnterObserver;
import com.vaadin.flow.router.Menu;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.springframework.orm.ObjectOptimisticLockingFailureException;
import org.vaadin.lineawesome.LineAwesomeIconUrl;

@PageTitle("Manufacturer")
@Route("manufacturer/:manufacturerID?/:action?(edit)")
@Menu(order = 2, icon = LineAwesomeIconUrl.HAMMER_SOLID)
public class ManufacturerView extends Div implements BeforeEnterObserver {

    private final String MANUFACTURER_ID = "manufacturerID";
    private final String MANUFACTURER_EDIT_ROUTE_TEMPLATE = "manufacturer/%s/edit";

    private final Grid<Manufacturer> grid = new Grid<>(Manufacturer.class, false);

    private TextField name;
    private TextField country;
    private TextField contactInfo;

    private final Button cancel = new Button("Cancel");
    private final Button save = new Button("Save");
    private final Button delete = new Button("Delete");

    private final BeanValidationBinder<Manufacturer> binder;

    private Manufacturer manufacturer;

    private List<Manufacturer> manufacturers;

    private final ManufacturerService manufacturerService;

    private ListDataProvider<Manufacturer> dataProvider;

    public ManufacturerView(ManufacturerService manufacturerService) {
        this.manufacturerService = manufacturerService;
        addClassNames("manufacturer-view");

        // Create UI
        SplitLayout splitLayout = new SplitLayout();

        createGridLayout(splitLayout);
        createEditorLayout(splitLayout);

        add(splitLayout);

        // Configure Grid
        grid.addColumn("name").setAutoWidth(true);
        grid.addColumn("country").setAutoWidth(true);
        grid.addColumn("contactInfo").setAutoWidth(true);
        //grid.setItems(query -> manufacturerService.list(VaadinSpringDataHelpers.toSpringPageRequest(query)).stream());
        grid.addThemeVariants(GridVariant.LUMO_NO_BORDER);

        manufacturers = manufacturerService.list();
        dataProvider = new ListDataProvider<>(manufacturers);
        grid.setDataProvider(dataProvider);

        // when a row is selected or deselected, populate form
        grid.asSingleSelect().addValueChangeListener(event -> {
            if (event.getValue() != null) {
                UI.getCurrent().navigate(String.format(MANUFACTURER_EDIT_ROUTE_TEMPLATE, event.getValue().getId()));
            } else {
                clearForm();
                UI.getCurrent().navigate(ManufacturerView.class);
            }
        });

        // Configure Form
        binder = new BeanValidationBinder<>(Manufacturer.class);


        addFilterRow();

        binder.bindInstanceFields(this);

        cancel.addClickListener(e -> {
            clearForm();
            refreshGrid();
        });

        save.addClickListener(e -> {
            try {
                if (this.manufacturer == null) {
                    this.manufacturer = new Manufacturer();
                }

                if (name.isEmpty() || country.isEmpty() || contactInfo.isEmpty()) {
                    Notification.show("Please fill all required fields");
                    return;
                }
                binder.writeBean(this.manufacturer);
                manufacturerService.save(this.manufacturer);
                clearForm();
                refreshGrid();
                Notification.show("Data updated");
                UI.getCurrent().navigate(ManufacturerView.class);
            } catch (ObjectOptimisticLockingFailureException exception) {
                Notification n = Notification.show(
                        "Error updating the data. Somebody else has updated the record while you were making changes.");
                n.setPosition(Position.MIDDLE);
                n.addThemeVariants(NotificationVariant.LUMO_ERROR);
            } catch (ValidationException validationException) {
                Notification.show("Failed to update the data. Check again that all values are valid");
            }
        });

        delete.addClickListener(e -> {
            try {
                if (this.manufacturer == null) {
                    return;
                }




                binder.writeBean(this.manufacturer);
                manufacturerService.delete(this.manufacturer.getId());
                clearForm();
                refreshGrid();
                Notification.show("Data deleted");
                UI.getCurrent().navigate(ManufacturerView.class);
            } catch (ObjectOptimisticLockingFailureException exception) {
                Notification n = Notification.show(
                        "Error updating the data. Somebody else has updated the record while you were making changes.");
                n.setPosition(Position.MIDDLE);
                n.addThemeVariants(NotificationVariant.LUMO_ERROR);
            } catch (ValidationException validationException) {
                Notification.show("Failed to update the data. Check again that all values are valid");
            }
        });
    }

    @Override
    public void beforeEnter(BeforeEnterEvent event) {
        Optional<Long> manufacturerId = event.getRouteParameters().get(MANUFACTURER_ID).map(Long::parseLong);
        if (manufacturerId.isPresent()) {
            Optional<Manufacturer> manufacturerFromBackend = manufacturerService.get(manufacturerId.get());
            if (manufacturerFromBackend.isPresent()) {
                populateForm(manufacturerFromBackend.get());
            } else {
                Notification.show(
                        String.format("The requested manufacturer was not found, ID = %s", manufacturerId.get()), 3000,
                        Notification.Position.BOTTOM_START);
                // when a row is selected but the data is no longer available,
                // refresh grid
                refreshGrid();
                event.forwardTo(ManufacturerView.class);
            }
        }
    }


    private void addFilterRow() {
        HeaderRow headerRow = grid.appendHeaderRow();

        // Filter for name column
        nameFilter = new TextField();
        nameFilter.addValueChangeListener(event -> {
            String filterValue = ((TextField) event.getSource()).getValue();

            if (filterValue.isEmpty()) {
                dataProvider.clearFilters();
            }
            else {
                dataProvider.setFilter(manufacturer -> manufacturer.getName() != null && manufacturer.getName().toLowerCase().contains(filterValue.toLowerCase()));
            }
            clearOtherFilters(nameFilter);
            clearForm();
            refreshGrid();
        });
        nameFilter.setPlaceholder("Filter");
        nameFilter.setWidthFull();
        headerRow.getCell(grid.getColumnByKey("name")).setComponent(nameFilter);

        // Filter for country column
        countryFilter = new TextField();
        countryFilter.addValueChangeListener(event -> {
            String filterValue = ((TextField) event.getSource()).getValue();

            if(filterValue.isEmpty()) {
                dataProvider.clearFilters();
            } else {
                dataProvider.setFilter(manufacturer ->  manufacturer.getCountry() != null && manufacturer.getCountry().toLowerCase().contains(filterValue.toLowerCase()));
            }
            clearOtherFilters(countryFilter);
            clearForm();
            refreshGrid();
        });
        countryFilter.setPlaceholder("Filter");
        countryFilter.setWidthFull();
        headerRow.getCell(grid.getColumnByKey("country")).setComponent(countryFilter);

        // Filter for contactInfo column
        contactInfoFilter = new TextField();
        contactInfoFilter.addValueChangeListener(event -> {
            String filterValue = ((TextField) event.getSource()).getValue();
            dataProvider.setFilter(manufacturer -> manufacturer.getContactInfo() != null && manufacturer.getContactInfo().toLowerCase().contains(filterValue.toLowerCase()));
            clearOtherFilters(contactInfoFilter);
            clearForm();
            refreshGrid();
        });
        contactInfoFilter.setPlaceholder("Filter");
        contactInfoFilter.setWidthFull();
        headerRow.getCell(grid.getColumnByKey("contactInfo")).setComponent(contactInfoFilter);
    }

    private void clearOtherFilters(TextField currentFilter) {
        if (currentFilter != nameFilter) {
            nameFilter.clear();
        }
        if (currentFilter != countryFilter) {
            countryFilter.clear();
        }
        if (currentFilter != contactInfoFilter) {
            contactInfoFilter.clear();
        }
    }


    private void createEditorLayout(SplitLayout splitLayout) {
        Div editorLayoutDiv = new Div();
        editorLayoutDiv.setClassName("editor-layout");

        Div editorDiv = new Div();
        editorDiv.setClassName("editor");
        editorLayoutDiv.add(editorDiv);

        FormLayout formLayout = new FormLayout();
        name = new TextField("Name");
        country = new TextField("Country");
        contactInfo = new TextField("Contact Info");
        formLayout.add(name, country, contactInfo);

        editorDiv.add(formLayout);
        createButtonLayout(editorLayoutDiv);

        splitLayout.addToSecondary(editorLayoutDiv);
    }

    private void createButtonLayout(Div editorLayoutDiv) {
        HorizontalLayout buttonLayout = new HorizontalLayout();
        buttonLayout.setClassName("button-layout");
        cancel.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
        save.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        delete.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        buttonLayout.add(save, cancel, delete);
        editorLayoutDiv.add(buttonLayout);
    }

    private void createGridLayout(SplitLayout splitLayout) {
        Div wrapper = new Div();
        wrapper.setClassName("grid-wrapper");
        splitLayout.addToPrimary(wrapper);
        wrapper.add(grid);
    }

    private void refreshGrid() {
        SerializablePredicate<Manufacturer> currentFilter = dataProvider.getFilter();

        // 2. Обновить список
        manufacturers = manufacturerService.list();


        // 3. Создать новый dataProvider и применить фильтр
        dataProvider = new ListDataProvider<>(manufacturers);
        grid.setDataProvider(dataProvider);

        dataProvider.setFilter(currentFilter);

        //  grid.select(null);
        dataProvider.refreshAll();
    }

    private void clearForm() {
        populateForm(null);
    }

    private void populateForm(Manufacturer value) {
        this.manufacturer = value;
        binder.readBean(this.manufacturer);
    }

    private TextField nameFilter;
    private TextField countryFilter;
    private TextField contactInfoFilter;
}