package de.votian.web.view;

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.html.H3;
import com.vaadin.flow.component.html.Paragraph;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.notification.NotificationVariant;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.tabs.Tab;
import com.vaadin.flow.component.tabs.Tabs;
import com.vaadin.flow.component.textfield.IntegerField;
import com.vaadin.flow.component.textfield.TextArea;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import de.votian.web.model.SessionData;
import de.votian.web.service.RestClientService;
import org.springframework.core.ParameterizedTypeReference;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Route(value = "groups-filters", layout = MainLayout.class)
@PageTitle("Votian - Gruppen und Filter")
public class GroupFilterAdminView extends VerticalLayout {

    private final RestClientService restClient;
    private final SessionData sessionData;

    private final Grid<GroupRow> groupGrid = new Grid<>(GroupRow.class, false);
    private final TextField groupNameField = new TextField("Gruppenname");
    private final Checkbox groupGlobalField = new Checkbox("Fuer alle Niederlassungen sichtbar");
    private final Paragraph groupInfo = new Paragraph();
    private final Button groupNewButton = new Button("Neu");
    private final Button groupSaveButton = new Button("Speichern");
    private final Button groupDeleteButton = new Button("Loeschen");
    private final List<GroupRow> groups = new ArrayList<>();

    private final Grid<FilterRow> filterGrid = new Grid<>(FilterRow.class, false);
    private final TextField filterShortField = new TextField("Kuerzel");
    private final TextField filterTextField = new TextField("Bezeichnung");
    private final ComboBox<FilterTypeOption> filterTypeField = new ComboBox<>("Art");
    private final ComboBox<FilterStatusOption> filterStatusField = new ComboBox<>("Typ");
    private final IntegerField filterSortField = new IntegerField("Sortierung");
    private final TextArea filterLongTextField = new TextArea("Langtext");
    private final Paragraph filterInfo = new Paragraph();
    private final Button filterNewButton = new Button("Neu");
    private final Button filterSaveButton = new Button("Speichern");
    private final Button filterDeleteButton = new Button("Loeschen");
    private final List<FilterRow> filters = new ArrayList<>();

    private Long selectedGroupId;
    private boolean selectedGroupReadonly;
    private Long selectedFilterId;

    public GroupFilterAdminView(RestClientService restClient, SessionData sessionData) {
        this.restClient = restClient;
        this.sessionData = sessionData;

        setSizeFull();
        setPadding(true);
        setSpacing(true);

        configureGroupGrid();
        configureFilterGrid();
        configureForms();
        configureActions();

        Tab groupsTab = new Tab("Gruppen");
        Tab filtersTab = new Tab("Filter");
        Tabs tabs = new Tabs(groupsTab, filtersTab);

        VerticalLayout groupsContent = buildGroupsContent();
        VerticalLayout filtersContent = buildFiltersContent();
        filtersContent.setVisible(false);

        tabs.addSelectedChangeListener(event -> {
            groupsContent.setVisible(event.getSelectedTab() == groupsTab);
            filtersContent.setVisible(event.getSelectedTab() == filtersTab);
        });

        add(new H3("Gruppen und Filter"), tabs, groupsContent, filtersContent);
        expand(groupsContent, filtersContent);

        loadGroups();
        loadFilters();
    }

    private void configureGroupGrid() {
        groupGrid.addColumn(GroupRow::name).setHeader("Gruppe").setAutoWidth(true).setFrozen(true);
        groupGrid.addColumn(GroupRow::visibilityLabel).setHeader("Sichtbarkeit").setAutoWidth(true);
        groupGrid.addColumn(GroupRow::usageCount).setHeader("Zuordnungen").setAutoWidth(true);
        groupGrid.addColumn(GroupRow::usageSummary).setHeader("Verwendung").setFlexGrow(1);
        groupGrid.addColumn(row -> row.readonly() ? "Ja" : "").setHeader("Readonly").setAutoWidth(true);
        groupGrid.setSizeFull();
        groupGrid.asSingleSelect().addValueChangeListener(event -> fillGroupForm(event.getValue()));
    }

    private void configureFilterGrid() {
        filterGrid.addColumn(FilterRow::shortCode).setHeader("Kuerzel").setAutoWidth(true).setFrozen(true);
        filterGrid.addColumn(FilterRow::text).setHeader("Bezeichnung").setAutoWidth(true);
        filterGrid.addColumn(FilterRow::typeLabel).setHeader("Art").setAutoWidth(true);
        filterGrid.addColumn(FilterRow::statusLabel).setHeader("Typ").setAutoWidth(true);
        filterGrid.addColumn(FilterRow::sort).setHeader("Sort.").setAutoWidth(true);
        filterGrid.addColumn(FilterRow::usageSummary).setHeader("Verwendung").setFlexGrow(1);
        filterGrid.setSizeFull();
        filterGrid.asSingleSelect().addValueChangeListener(event -> fillFilterForm(event.getValue()));
    }

    private void configureForms() {
        groupNameField.setWidthFull();
        groupInfo.getStyle().set("margin", "0");

        filterTypeField.setItems(
                new FilterTypeOption(0, "Fahrzeugfilter"),
                new FilterTypeOption(1, "Transporteursfilter")
        );
        filterTypeField.setItemLabelGenerator(FilterTypeOption::label);
        filterTypeField.setValue(new FilterTypeOption(0, "Fahrzeugfilter"));

        filterStatusField.setItems(
                new FilterStatusOption(1, "Pflichtfilter"),
                new FilterStatusOption(2, "Optional")
        );
        filterStatusField.setItemLabelGenerator(FilterStatusOption::label);
        filterStatusField.setValue(new FilterStatusOption(2, "Optional"));

        filterLongTextField.setWidthFull();
        filterLongTextField.setMinHeight("140px");
        filterInfo.getStyle().set("margin", "0");
    }

    private void configureActions() {
        groupSaveButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        groupDeleteButton.addThemeVariants(ButtonVariant.LUMO_ERROR);
        filterSaveButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        filterDeleteButton.addThemeVariants(ButtonVariant.LUMO_ERROR);

        groupNewButton.addClickListener(event -> clearGroupForm());
        groupSaveButton.addClickListener(event -> saveGroup());
        groupDeleteButton.addClickListener(event -> deleteGroup());

        filterNewButton.addClickListener(event -> clearFilterForm());
        filterSaveButton.addClickListener(event -> saveFilter());
        filterDeleteButton.addClickListener(event -> deleteFilter());

        refreshGroupButtons();
        refreshFilterButtons();
    }

    private VerticalLayout buildGroupsContent() {
        FormLayout form = new FormLayout();
        form.setResponsiveSteps(
                new FormLayout.ResponsiveStep("0", 1),
                new FormLayout.ResponsiveStep("700px", 2)
        );
        form.add(groupNameField, groupGlobalField);

        HorizontalLayout actions = new HorizontalLayout(groupNewButton, groupSaveButton, groupDeleteButton);
        VerticalLayout content = new VerticalLayout(
                new Paragraph("Der Gruppenkatalog entspricht der Legacy-Tabelle `groups`. Nicht schreibbare Legacy-Gruppen bleiben sichtbar, aber gesperrt."),
                form,
                groupInfo,
                actions,
                groupGrid
        );
        content.setPadding(false);
        content.setSpacing(true);
        content.setSizeFull();
        content.expand(groupGrid);
        return content;
    }

    private VerticalLayout buildFiltersContent() {
        FormLayout form = new FormLayout();
        form.setResponsiveSteps(
                new FormLayout.ResponsiveStep("0", 1),
                new FormLayout.ResponsiveStep("900px", 2)
        );
        form.add(filterShortField, filterTextField, filterTypeField, filterStatusField, filterSortField, filterLongTextField);
        form.setColspan(filterLongTextField, 2);

        HorizontalLayout actions = new HorizontalLayout(filterNewButton, filterSaveButton, filterDeleteButton);
        VerticalLayout content = new VerticalLayout(
                new Paragraph("Filter pflegen den Legacy-Katalog `courierfilter`. Beim Loeschen werden Kunden-, Kurier- und Fahrzeugzuordnungen bereinigt."),
                form,
                filterInfo,
                actions,
                filterGrid
        );
        content.setPadding(false);
        content.setSpacing(true);
        content.setSizeFull();
        content.expand(filterGrid);
        return content;
    }

    private void loadGroups() {
        if (sessionData.getHeadquartersId() == null) {
            return;
        }
        try {
            List<LinkedHashMap<String, Object>> result = restClient.getList(
                    "/group-filter-admin/groups?hqId=" + sessionData.getHeadquartersId(),
                    new ParameterizedTypeReference<>() {}
            );
            groups.clear();
            for (Map<String, Object> row : result) {
                Long id = toLong(row.get("id"));
                if (id == null) {
                    continue;
                }
                groups.add(new GroupRow(
                        id,
                        str(row.get("name")),
                        bool(row.get("globalVisible")),
                        bool(row.get("readonly")),
                        toLong(row.get("usageCount")) != null ? toLong(row.get("usageCount")) : 0L,
                        str(row.get("usageSummary"))
                ));
            }
            groupGrid.setItems(groups);
            if (selectedGroupId != null) {
                groups.stream()
                        .filter(row -> row.id().equals(selectedGroupId))
                        .findFirst()
                        .ifPresent(row -> groupGrid.asSingleSelect().setValue(row));
            }
        } catch (Exception e) {
            showError("Gruppen konnten nicht geladen werden: " + e.getMessage());
        }
    }

    private void loadFilters() {
        if (sessionData.getHeadquartersId() == null) {
            return;
        }
        try {
            List<LinkedHashMap<String, Object>> result = restClient.getList(
                    "/group-filter-admin/filters?hqId=" + sessionData.getHeadquartersId(),
                    new ParameterizedTypeReference<>() {}
            );
            filters.clear();
            for (Map<String, Object> row : result) {
                Long id = toLong(row.get("id"));
                if (id == null) {
                    continue;
                }
                filters.add(new FilterRow(
                        id,
                        toInteger(row.get("type")) != null ? toInteger(row.get("type")) : 0,
                        str(row.get("typeLabel")),
                        toInteger(row.get("status")) != null ? toInteger(row.get("status")) : 2,
                        str(row.get("statusLabel")),
                        str(row.get("shortCode")),
                        str(row.get("text")),
                        toInteger(row.get("sort")) != null ? toInteger(row.get("sort")) : 0,
                        str(row.get("longText")),
                        toLong(row.get("usageCount")) != null ? toLong(row.get("usageCount")) : 0L,
                        str(row.get("usageSummary"))
                ));
            }
            filterGrid.setItems(filters);
            if (selectedFilterId != null) {
                filters.stream()
                        .filter(row -> row.id().equals(selectedFilterId))
                        .findFirst()
                        .ifPresent(row -> filterGrid.asSingleSelect().setValue(row));
            }
        } catch (Exception e) {
            showError("Filter konnten nicht geladen werden: " + e.getMessage());
        }
    }

    private void fillGroupForm(GroupRow row) {
        if (row == null) {
            clearGroupForm();
            return;
        }
        selectedGroupId = row.id();
        selectedGroupReadonly = row.readonly();
        groupNameField.setValue(row.name());
        groupGlobalField.setValue(row.globalVisible());
        groupInfo.setText(row.usageSummary());
        refreshGroupButtons();
    }

    private void clearGroupForm() {
        selectedGroupId = null;
        selectedGroupReadonly = false;
        groupGrid.asSingleSelect().clear();
        groupNameField.clear();
        groupGlobalField.setValue(false);
        groupInfo.setText("Neue Gruppe anlegen oder bestehende Gruppe aus der Liste bearbeiten.");
        refreshGroupButtons();
    }

    private void saveGroup() {
        if (sessionData.getHeadquartersId() == null) {
            return;
        }
        try {
            Map<String, Object> request = new LinkedHashMap<>();
            request.put("hqId", sessionData.getHeadquartersId());
            request.put("name", groupNameField.getValue());
            request.put("globalVisible", groupGlobalField.getValue());

            if (selectedGroupId == null) {
                restClient.post("/group-filter-admin/groups", request, LinkedHashMap.class);
            } else {
                restClient.put("/group-filter-admin/groups/" + selectedGroupId, request);
            }
            Notification.show("Gruppe gespeichert.", 3000, Notification.Position.MIDDLE)
                    .addThemeVariants(NotificationVariant.LUMO_SUCCESS);
            clearGroupForm();
            loadGroups();
        } catch (Exception e) {
            showError("Gruppe konnte nicht gespeichert werden: " + e.getMessage());
        }
    }

    private void deleteGroup() {
        if (selectedGroupId == null || sessionData.getHeadquartersId() == null) {
            return;
        }
        try {
            restClient.delete("/group-filter-admin/groups/" + selectedGroupId + "?hqId=" + sessionData.getHeadquartersId());
            Notification.show("Gruppe geloescht.", 3000, Notification.Position.MIDDLE)
                    .addThemeVariants(NotificationVariant.LUMO_SUCCESS);
            clearGroupForm();
            loadGroups();
        } catch (Exception e) {
            showError("Gruppe konnte nicht geloescht werden: " + e.getMessage());
        }
    }

    private void fillFilterForm(FilterRow row) {
        if (row == null) {
            clearFilterForm();
            return;
        }
        selectedFilterId = row.id();
        filterShortField.setValue(row.shortCode());
        filterShortField.setReadOnly(true);
        filterTextField.setValue(row.text());
        filterTypeField.setValue(new FilterTypeOption(row.type(), row.typeLabel()));
        filterStatusField.setValue(new FilterStatusOption(row.status(), row.statusLabel()));
        filterSortField.setValue(row.sort());
        filterLongTextField.setValue(row.longText());
        filterInfo.setText(row.usageSummary());
        refreshFilterButtons();
    }

    private void clearFilterForm() {
        selectedFilterId = null;
        filterGrid.asSingleSelect().clear();
        filterShortField.clear();
        filterShortField.setReadOnly(false);
        filterTextField.clear();
        filterTypeField.setValue(new FilterTypeOption(0, "Fahrzeugfilter"));
        filterStatusField.setValue(new FilterStatusOption(2, "Optional"));
        filterSortField.clear();
        filterLongTextField.clear();
        filterInfo.setText("Neuen Filter anlegen oder bestehenden Filter aus der Liste bearbeiten.");
        refreshFilterButtons();
    }

    private void saveFilter() {
        if (sessionData.getHeadquartersId() == null) {
            return;
        }
        try {
            Map<String, Object> request = new LinkedHashMap<>();
            request.put("hqId", sessionData.getHeadquartersId());
            request.put("shortCode", filterShortField.getValue());
            request.put("text", filterTextField.getValue());
            request.put("type", filterTypeField.getValue() != null ? filterTypeField.getValue().code() : 0);
            request.put("status", filterStatusField.getValue() != null ? filterStatusField.getValue().code() : 2);
            request.put("sort", filterSortField.getValue());
            request.put("longText", filterLongTextField.getValue());

            if (selectedFilterId == null) {
                restClient.post("/group-filter-admin/filters", request, LinkedHashMap.class);
            } else {
                restClient.put("/group-filter-admin/filters/" + selectedFilterId, request);
            }
            Notification.show("Filter gespeichert.", 3000, Notification.Position.MIDDLE)
                    .addThemeVariants(NotificationVariant.LUMO_SUCCESS);
            clearFilterForm();
            loadFilters();
        } catch (Exception e) {
            showError("Filter konnte nicht gespeichert werden: " + e.getMessage());
        }
    }

    private void deleteFilter() {
        if (selectedFilterId == null || sessionData.getHeadquartersId() == null) {
            return;
        }
        try {
            restClient.delete("/group-filter-admin/filters/" + selectedFilterId + "?hqId=" + sessionData.getHeadquartersId());
            Notification.show("Filter geloescht.", 3000, Notification.Position.MIDDLE)
                    .addThemeVariants(NotificationVariant.LUMO_SUCCESS);
            clearFilterForm();
            loadFilters();
        } catch (Exception e) {
            showError("Filter konnte nicht geloescht werden: " + e.getMessage());
        }
    }

    private void refreshGroupButtons() {
        boolean editable = !selectedGroupReadonly;
        groupSaveButton.setEnabled(editable);
        groupDeleteButton.setEnabled(selectedGroupId != null && editable);
    }

    private void refreshFilterButtons() {
        filterDeleteButton.setEnabled(selectedFilterId != null);
    }

    private void showError(String message) {
        Notification.show(message, 5000, Notification.Position.MIDDLE)
                .addThemeVariants(NotificationVariant.LUMO_ERROR);
    }

    private Long toLong(Object value) {
        if (value instanceof Number number) {
            return number.longValue();
        }
        try {
            return value != null ? Long.parseLong(value.toString()) : null;
        } catch (NumberFormatException e) {
            return null;
        }
    }

    private Integer toInteger(Object value) {
        if (value instanceof Number number) {
            return number.intValue();
        }
        try {
            return value != null ? Integer.parseInt(value.toString()) : null;
        } catch (NumberFormatException e) {
            return null;
        }
    }

    private boolean bool(Object value) {
        return Boolean.TRUE.equals(value) || (value != null && "true".equalsIgnoreCase(value.toString()));
    }

    private String str(Object value) {
        return value != null ? value.toString() : "";
    }

    private record GroupRow(Long id,
                            String name,
                            boolean globalVisible,
                            boolean readonly,
                            long usageCount,
                            String usageSummary) {
        private String visibilityLabel() {
            return globalVisible ? "Alle Niederlassungen" : "Nur aktuelle Niederlassung";
        }
    }

    private record FilterRow(Long id,
                             int type,
                             String typeLabel,
                             int status,
                             String statusLabel,
                             String shortCode,
                             String text,
                             int sort,
                             String longText,
                             long usageCount,
                             String usageSummary) {
    }

    private record FilterTypeOption(int code, String label) {
    }

    private record FilterStatusOption(int code, String label) {
    }
}
