package de.votian.web.view;

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.grid.Grid;
import com.vaadin.flow.component.html.H3;
import com.vaadin.flow.component.html.H4;
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.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.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

@Route(value = "meta-admin", layout = MainLayout.class)
@PageTitle("Votian - Formulare")
public class MetaFieldAdminView extends VerticalLayout {

    private final RestClientService restClient;
    private final SessionData sessionData;

    private final Grid<CategoryRow> categoryGrid = new Grid<>(CategoryRow.class, false);
    private final Grid<FieldRow> fieldGrid = new Grid<>(FieldRow.class, false);
    private final Grid<TemplateRow> templateGrid = new Grid<>(TemplateRow.class, false);
    private final Grid<CategoryFieldRow> categoryFieldGrid = new Grid<>(CategoryFieldRow.class, false);

    private final TextField categoryMnemonicField = new TextField("Kuerzel");
    private final TextField categoryDescriptionField = new TextField("Bezeichnung");
    private final ComboBox<TemplateOption> categoryTemplateField = new ComboBox<>("Vorlage");
    private final ComboBox<FieldOption> categoryFieldSelection = new ComboBox<>("Globales Feld");

    private final TextField fieldFilter = new TextField("Anzeigefilter");
    private final TextField fieldTypeField = new TextField("Typ");
    private final TextField fieldNameField = new TextField("Name");

    private final TextField templateNameField = new TextField("Name");
    private final TextArea templateContentField = new TextArea("Inhalt");

    private final Button categoryNewButton = new Button("Neu");
    private final Button categorySaveButton = new Button("Speichern");
    private final Button categoryFieldAddButton = new Button("Feld hinzufuegen");
    private final Button categoryFieldUpButton = new Button("Nach oben");
    private final Button categoryFieldDownButton = new Button("Nach unten");
    private final Button categoryFieldRemoveButton = new Button("Entfernen");

    private final Button fieldNewButton = new Button("Neu");
    private final Button fieldSaveButton = new Button("Speichern");
    private final Button fieldLoadButton = new Button("Anzeigen");

    private final Button templateNewButton = new Button("Neu");
    private final Button templateSaveButton = new Button("Speichern");

    private final List<CategoryRow> categories = new ArrayList<>();
    private final List<FieldRow> fieldGridRows = new ArrayList<>();
    private final List<FieldOption> allFieldOptions = new ArrayList<>();
    private final List<TemplateRow> templates = new ArrayList<>();
    private final List<TemplateOption> templateOptions = new ArrayList<>();
    private final List<CategoryFieldRow> categoryFieldRows = new ArrayList<>();

    private Long selectedCategoryId;
    private Long selectedFieldId;
    private Long selectedTemplateId;

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

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

        configureGrids();
        configureFields();
        configureButtons();

        Tab categoriesTab = new Tab("Formulare");
        Tab fieldsTab = new Tab("Globale Felder");
        Tab templatesTab = new Tab("Vorlagen");
        Tabs tabs = new Tabs(categoriesTab, fieldsTab, templatesTab);

        VerticalLayout categoriesContent = buildCategoriesContent();
        VerticalLayout fieldsContent = buildFieldsContent();
        VerticalLayout templatesContent = buildTemplatesContent();
        fieldsContent.setVisible(false);
        templatesContent.setVisible(false);

        tabs.addSelectedChangeListener(event -> {
            categoriesContent.setVisible(event.getSelectedTab() == categoriesTab);
            fieldsContent.setVisible(event.getSelectedTab() == fieldsTab);
            templatesContent.setVisible(event.getSelectedTab() == templatesTab);
        });

        add(new H3("Formulare und Metafelder"), tabs, categoriesContent, fieldsContent, templatesContent);
        expand(categoriesContent, fieldsContent, templatesContent);

        loadTemplates();
        loadFieldOptions();
        loadFieldGrid();
        loadCategories();
    }

    private void configureGrids() {
        categoryGrid.addColumn(CategoryRow::mnemonic).setHeader("Kuerzel").setAutoWidth(true).setFrozen(true);
        categoryGrid.addColumn(CategoryRow::description).setHeader("Bezeichnung").setFlexGrow(1);
        categoryGrid.addColumn(CategoryRow::templateName).setHeader("Vorlage").setAutoWidth(true);
        categoryGrid.addColumn(CategoryRow::fieldCount).setHeader("Felder").setAutoWidth(true);
        categoryGrid.setHeight("260px");
        categoryGrid.asSingleSelect().addValueChangeListener(event -> fillCategoryForm(event.getValue()));

        categoryFieldGrid.addColumn(CategoryFieldRow::sort).setHeader("Sort.").setAutoWidth(true).setFrozen(true);
        categoryFieldGrid.addColumn(CategoryFieldRow::fieldName).setHeader("Feld").setFlexGrow(1);
        categoryFieldGrid.addColumn(CategoryFieldRow::fieldType).setHeader("Typ").setAutoWidth(true);
        categoryFieldGrid.setHeight("240px");

        fieldGrid.addColumn(FieldRow::id).setHeader("Nr.").setAutoWidth(true).setFrozen(true);
        fieldGrid.addColumn(FieldRow::name).setHeader("Name").setFlexGrow(1);
        fieldGrid.addColumn(FieldRow::type).setHeader("Typ").setFlexGrow(1);
        fieldGrid.setHeight("320px");
        fieldGrid.asSingleSelect().addValueChangeListener(event -> fillFieldForm(event.getValue()));

        templateGrid.addColumn(TemplateRow::name).setHeader("Name").setFlexGrow(1).setFrozen(true);
        templateGrid.addColumn(TemplateRow::usageCount).setHeader("Verwendung").setAutoWidth(true);
        templateGrid.setHeight("260px");
        templateGrid.asSingleSelect().addValueChangeListener(event -> fillTemplateForm(event.getValue()));
    }

    private void configureFields() {
        categoryTemplateField.setItemLabelGenerator(TemplateOption::label);
        categoryTemplateField.setWidthFull();

        categoryFieldSelection.setItemLabelGenerator(FieldOption::label);
        categoryFieldSelection.setWidth("420px");

        fieldFilter.setClearButtonVisible(true);
        fieldFilter.setWidth("320px");
        fieldTypeField.setWidthFull();
        fieldNameField.setWidthFull();

        templateNameField.setWidthFull();
        templateContentField.setWidthFull();
        templateContentField.setMinHeight("260px");
    }

    private void configureButtons() {
        categorySaveButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        categoryFieldAddButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        fieldSaveButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        templateSaveButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);

        categoryNewButton.addClickListener(event -> clearCategoryForm());
        categorySaveButton.addClickListener(event -> saveCategory());
        categoryFieldAddButton.addClickListener(event -> addCategoryField());
        categoryFieldUpButton.addClickListener(event -> moveCategoryField(-1));
        categoryFieldDownButton.addClickListener(event -> moveCategoryField(1));
        categoryFieldRemoveButton.addClickListener(event -> removeCategoryField());

        fieldNewButton.addClickListener(event -> clearFieldForm());
        fieldSaveButton.addClickListener(event -> saveField());
        fieldLoadButton.addClickListener(event -> loadFieldGrid());

        templateNewButton.addClickListener(event -> clearTemplateForm());
        templateSaveButton.addClickListener(event -> saveTemplate());
    }

    private VerticalLayout buildCategoriesContent() {
        FormLayout categoryForm = new FormLayout();
        categoryForm.setResponsiveSteps(
                new FormLayout.ResponsiveStep("0", 1),
                new FormLayout.ResponsiveStep("850px", 3)
        );
        categoryForm.add(categoryMnemonicField, categoryDescriptionField, categoryTemplateField);

        HorizontalLayout categoryActions = new HorizontalLayout(categoryNewButton, categorySaveButton);
        HorizontalLayout fieldActions = new HorizontalLayout(
                categoryFieldSelection,
                categoryFieldAddButton,
                categoryFieldUpButton,
                categoryFieldDownButton,
                categoryFieldRemoveButton
        );
        fieldActions.setAlignItems(Alignment.BASELINE);

        VerticalLayout content = new VerticalLayout(
                new Paragraph("Der Workspace pflegt die Legacy-Tabellen `metafieldcategory`, `metafieldkey`, `metafieldtemplate` und `metafieldcategorykey` direkt kompatibel weiter."),
                new H4("Formulare"),
                categoryGrid,
                categoryForm,
                categoryActions,
                new H4("Formularfelder"),
                fieldActions,
                categoryFieldGrid
        );
        content.setPadding(false);
        content.setSpacing(true);
        content.setSizeFull();
        return content;
    }

    private VerticalLayout buildFieldsContent() {
        FormLayout form = new FormLayout();
        form.setResponsiveSteps(
                new FormLayout.ResponsiveStep("0", 1),
                new FormLayout.ResponsiveStep("900px", 2)
        );
        form.add(fieldTypeField, fieldNameField);

        HorizontalLayout filterBar = new HorizontalLayout(fieldFilter, fieldLoadButton);
        filterBar.setAlignItems(Alignment.BASELINE);
        HorizontalLayout actions = new HorizontalLayout(fieldNewButton, fieldSaveButton);

        VerticalLayout content = new VerticalLayout(
                new Paragraph("Globale Felder bleiben mandantenunabhaengig. Die Filterung entspricht dem Legacy-Editor nach Feldnamenpraefix."),
                filterBar,
                fieldGrid,
                form,
                actions
        );
        content.setPadding(false);
        content.setSpacing(true);
        content.setSizeFull();
        return content;
    }

    private VerticalLayout buildTemplatesContent() {
        FormLayout form = new FormLayout();
        form.setResponsiveSteps(new FormLayout.ResponsiveStep("0", 1));
        form.add(templateNameField, templateContentField);

        HorizontalLayout actions = new HorizontalLayout(templateNewButton, templateSaveButton);
        VerticalLayout content = new VerticalLayout(
                new Paragraph("Vorlagen editieren direkt `mtft_content` und koennen anschliessend den Formularen zugewiesen werden."),
                templateGrid,
                form,
                actions
        );
        content.setPadding(false);
        content.setSpacing(true);
        content.setSizeFull();
        return content;
    }

    private void loadCategories() {
        Long headquartersId = sessionData.getHeadquartersId();
        if (headquartersId == null) {
            return;
        }
        try {
            List<LinkedHashMap<String, Object>> result = restClient.getList(
                    "/meta-admin/categories?hqId=" + headquartersId,
                    new ParameterizedTypeReference<>() {}
            );
            categories.clear();
            for (Map<String, Object> row : result) {
                Long id = toLong(row.get("id"));
                if (id == null) {
                    continue;
                }
                categories.add(new CategoryRow(
                        id,
                        str(row.get("mnemonic")),
                        str(row.get("description")),
                        toLong(row.get("templateId")),
                        str(row.get("templateName")),
                        toLong(row.get("fieldCount")) != null ? toLong(row.get("fieldCount")) : 0L
                ));
            }
            categoryGrid.setItems(categories);
            reselectCategory();
            if (selectedCategoryId == null && !categories.isEmpty()) {
                categoryGrid.select(categories.get(0));
            }
        } catch (Exception e) {
            showError("Formulare konnten nicht geladen werden: " + e.getMessage());
        }
    }

    private void loadFieldGrid() {
        Long headquartersId = sessionData.getHeadquartersId();
        if (headquartersId == null) {
            return;
        }
        try {
            String path = "/meta-admin/fields?hqId=" + headquartersId;
            if (!fieldFilter.getValue().isBlank()) {
                path += "&filter=" + url(fieldFilter.getValue().trim());
            }
            List<LinkedHashMap<String, Object>> result = restClient.getList(path, new ParameterizedTypeReference<>() {});
            fieldGridRows.clear();
            for (Map<String, Object> row : result) {
                Long id = toLong(row.get("id"));
                if (id == null) {
                    continue;
                }
                fieldGridRows.add(new FieldRow(
                        id,
                        str(row.get("type")),
                        str(row.get("name"))
                ));
            }
            fieldGrid.setItems(fieldGridRows);
            reselectField();
        } catch (Exception e) {
            showError("Globale Felder konnten nicht geladen werden: " + e.getMessage());
        }
    }

    private void loadFieldOptions() {
        Long headquartersId = sessionData.getHeadquartersId();
        if (headquartersId == null) {
            return;
        }
        try {
            List<LinkedHashMap<String, Object>> result = restClient.getList(
                    "/meta-admin/fields?hqId=" + headquartersId,
                    new ParameterizedTypeReference<>() {}
            );
            allFieldOptions.clear();
            for (Map<String, Object> row : result) {
                Long id = toLong(row.get("id"));
                if (id == null) {
                    continue;
                }
                allFieldOptions.add(new FieldOption(
                        id,
                        str(row.get("name")),
                        str(row.get("type"))
                ));
            }
            refreshCategoryFieldSelection();
        } catch (Exception e) {
            showError("Feldoptionen konnten nicht geladen werden: " + e.getMessage());
        }
    }

    private void loadTemplates() {
        Long headquartersId = sessionData.getHeadquartersId();
        if (headquartersId == null) {
            return;
        }
        try {
            List<LinkedHashMap<String, Object>> result = restClient.getList(
                    "/meta-admin/templates?hqId=" + headquartersId,
                    new ParameterizedTypeReference<>() {}
            );
            templates.clear();
            templateOptions.clear();
            templateOptions.add(new TemplateOption(null, "(keine Vorlage)"));
            for (Map<String, Object> row : result) {
                Long id = toLong(row.get("id"));
                if (id == null) {
                    continue;
                }
                TemplateRow template = new TemplateRow(
                        id,
                        str(row.get("name")),
                        str(row.get("content")),
                        toLong(row.get("usageCount")) != null ? toLong(row.get("usageCount")) : 0L
                );
                templates.add(template);
                templateOptions.add(new TemplateOption(id, template.name()));
            }
            templateGrid.setItems(templates);
            categoryTemplateField.setItems(templateOptions);
            categoryTemplateField.setValue(templateOptions.get(0));
            reselectTemplate();
        } catch (Exception e) {
            showError("Vorlagen konnten nicht geladen werden: " + e.getMessage());
        }
    }

    private void loadCategoryFields() {
        Long headquartersId = sessionData.getHeadquartersId();
        if (selectedCategoryId == null || headquartersId == null) {
            categoryFieldRows.clear();
            categoryFieldGrid.setItems(categoryFieldRows);
            refreshCategoryFieldSelection();
            return;
        }
        try {
            List<LinkedHashMap<String, Object>> result = restClient.getList(
                    "/meta-admin/categories/" + selectedCategoryId + "/fields?hqId=" + headquartersId,
                    new ParameterizedTypeReference<>() {}
            );
            categoryFieldRows.clear();
            for (Map<String, Object> row : result) {
                Long assignmentId = toLong(row.get("assignmentId"));
                Long fieldId = toLong(row.get("fieldId"));
                if (assignmentId == null || fieldId == null) {
                    continue;
                }
                categoryFieldRows.add(new CategoryFieldRow(
                        assignmentId,
                        fieldId,
                        str(row.get("fieldName")),
                        str(row.get("fieldType")),
                        toInteger(row.get("sort")) != null ? toInteger(row.get("sort")) : 0
                ));
            }
            categoryFieldGrid.setItems(categoryFieldRows);
            refreshCategoryFieldSelection();
        } catch (Exception e) {
            showError("Formularfelder konnten nicht geladen werden: " + e.getMessage());
        }
    }

    private void saveCategory() {
        Long headquartersId = sessionData.getHeadquartersId();
        if (headquartersId == null) {
            return;
        }
        try {
            Map<String, Object> request = new LinkedHashMap<>();
            request.put("hqId", headquartersId);
            request.put("mnemonic", categoryMnemonicField.getValue());
            request.put("description", categoryDescriptionField.getValue());
            TemplateOption template = categoryTemplateField.getValue();
            request.put("templateId", template != null ? template.id() : null);

            if (selectedCategoryId == null) {
                restClient.post("/meta-admin/categories", request, LinkedHashMap.class);
            } else {
                restClient.put("/meta-admin/categories/" + selectedCategoryId, request);
            }
            showSuccess("Formular gespeichert.");
            loadTemplates();
            loadCategories();
            loadCategoryFields();
        } catch (Exception e) {
            showError("Formular konnte nicht gespeichert werden: " + e.getMessage());
        }
    }

    private void saveField() {
        Long headquartersId = sessionData.getHeadquartersId();
        if (headquartersId == null) {
            return;
        }
        try {
            Map<String, Object> request = new LinkedHashMap<>();
            request.put("hqId", headquartersId);
            request.put("type", fieldTypeField.getValue());
            request.put("name", fieldNameField.getValue());

            if (selectedFieldId == null) {
                restClient.post("/meta-admin/fields", request, LinkedHashMap.class);
            } else {
                restClient.put("/meta-admin/fields/" + selectedFieldId, request);
            }
            showSuccess("Globales Feld gespeichert.");
            loadFieldOptions();
            loadFieldGrid();
            loadCategoryFields();
        } catch (Exception e) {
            showError("Globales Feld konnte nicht gespeichert werden: " + e.getMessage());
        }
    }

    private void saveTemplate() {
        Long headquartersId = sessionData.getHeadquartersId();
        if (headquartersId == null) {
            return;
        }
        try {
            Map<String, Object> request = new LinkedHashMap<>();
            request.put("hqId", headquartersId);
            request.put("name", templateNameField.getValue());
            request.put("content", templateContentField.getValue());

            if (selectedTemplateId == null) {
                restClient.post("/meta-admin/templates", request, LinkedHashMap.class);
            } else {
                restClient.put("/meta-admin/templates/" + selectedTemplateId, request);
            }
            showSuccess("Vorlage gespeichert.");
            loadTemplates();
            loadCategories();
        } catch (Exception e) {
            showError("Vorlage konnte nicht gespeichert werden: " + e.getMessage());
        }
    }

    private void addCategoryField() {
        Long headquartersId = sessionData.getHeadquartersId();
        FieldOption selectedField = categoryFieldSelection.getValue();
        if (selectedCategoryId == null || headquartersId == null || selectedField == null) {
            showError("Bitte Formular und Feld auswaehlen.");
            return;
        }
        try {
            Map<String, Object> request = new LinkedHashMap<>();
            request.put("hqId", headquartersId);
            request.put("fieldId", selectedField.id());
            restClient.post("/meta-admin/categories/" + selectedCategoryId + "/fields", request, LinkedHashMap.class);
            showSuccess("Formularfeld hinzugefuegt.");
            loadCategoryFields();
            loadCategories();
        } catch (Exception e) {
            showError("Formularfeld konnte nicht hinzugefuegt werden: " + e.getMessage());
        }
    }

    private void moveCategoryField(int direction) {
        CategoryFieldRow selected = categoryFieldGrid.asSingleSelect().getValue();
        Long headquartersId = sessionData.getHeadquartersId();
        if (selectedCategoryId == null || headquartersId == null || selected == null) {
            return;
        }
        int index = categoryFieldRows.indexOf(selected);
        int newIndex = index + direction;
        if (index < 0 || newIndex < 0 || newIndex >= categoryFieldRows.size()) {
            return;
        }
        List<CategoryFieldRow> reordered = new ArrayList<>(categoryFieldRows);
        reordered.remove(index);
        reordered.add(newIndex, selected);
        try {
            Map<String, Object> request = new LinkedHashMap<>();
            request.put("hqId", headquartersId);
            request.put("assignmentIds", reordered.stream().map(CategoryFieldRow::assignmentId).toList());
            restClient.put("/meta-admin/categories/" + selectedCategoryId + "/fields/order", request);
            loadCategoryFields();
            loadCategories();
        } catch (Exception e) {
            showError("Sortierung konnte nicht gespeichert werden: " + e.getMessage());
        }
    }

    private void removeCategoryField() {
        CategoryFieldRow selected = categoryFieldGrid.asSingleSelect().getValue();
        Long headquartersId = sessionData.getHeadquartersId();
        if (selected == null || headquartersId == null) {
            return;
        }
        try {
            restClient.delete("/meta-admin/category-fields/" + selected.assignmentId() + "?hqId=" + headquartersId);
            showSuccess("Formularfeld entfernt.");
            loadCategoryFields();
            loadCategories();
        } catch (Exception e) {
            showError("Formularfeld konnte nicht entfernt werden: " + e.getMessage());
        }
    }

    private void fillCategoryForm(CategoryRow row) {
        if (row == null) {
            clearCategoryForm();
            return;
        }
        selectedCategoryId = row.id();
        categoryMnemonicField.setValue(row.mnemonic());
        categoryDescriptionField.setValue(row.description());
        categoryTemplateField.setValue(templateOptions.stream()
                .filter(option -> Objects.equals(option.id(), row.templateId()))
                .findFirst()
                .orElse(templateOptions.get(0)));
        loadCategoryFields();
    }

    private void fillFieldForm(FieldRow row) {
        if (row == null) {
            clearFieldForm();
            return;
        }
        selectedFieldId = row.id();
        fieldTypeField.setValue(row.type());
        fieldNameField.setValue(row.name());
    }

    private void fillTemplateForm(TemplateRow row) {
        if (row == null) {
            clearTemplateForm();
            return;
        }
        selectedTemplateId = row.id();
        templateNameField.setValue(row.name());
        templateContentField.setValue(row.content());
    }

    private void clearCategoryForm() {
        selectedCategoryId = null;
        categoryGrid.asSingleSelect().clear();
        categoryMnemonicField.clear();
        categoryDescriptionField.clear();
        if (!templateOptions.isEmpty()) {
            categoryTemplateField.setValue(templateOptions.get(0));
        } else {
            categoryTemplateField.clear();
        }
        loadCategoryFields();
    }

    private void clearFieldForm() {
        selectedFieldId = null;
        fieldGrid.asSingleSelect().clear();
        fieldTypeField.clear();
        fieldNameField.clear();
    }

    private void clearTemplateForm() {
        selectedTemplateId = null;
        templateGrid.asSingleSelect().clear();
        templateNameField.clear();
        templateContentField.clear();
    }

    private void refreshCategoryFieldSelection() {
        if (selectedCategoryId == null) {
            categoryFieldSelection.clear();
            categoryFieldSelection.setItems(List.of());
            return;
        }
        List<Long> assignedFieldIds = categoryFieldRows.stream().map(CategoryFieldRow::fieldId).toList();
        List<FieldOption> available = allFieldOptions.stream()
                .filter(option -> !assignedFieldIds.contains(option.id()))
                .toList();
        categoryFieldSelection.setItems(available);
        if (!available.contains(categoryFieldSelection.getValue())) {
            categoryFieldSelection.clear();
        }
    }

    private void reselectCategory() {
        if (selectedCategoryId == null) {
            return;
        }
        categories.stream()
                .filter(row -> Objects.equals(row.id(), selectedCategoryId))
                .findFirst()
                .ifPresent(row -> categoryGrid.select(row));
    }

    private void reselectField() {
        if (selectedFieldId == null) {
            return;
        }
        fieldGridRows.stream()
                .filter(row -> Objects.equals(row.id(), selectedFieldId))
                .findFirst()
                .ifPresent(row -> fieldGrid.select(row));
    }

    private void reselectTemplate() {
        if (selectedTemplateId == null) {
            return;
        }
        templates.stream()
                .filter(row -> Objects.equals(row.id(), selectedTemplateId))
                .findFirst()
                .ifPresent(row -> templateGrid.select(row));
    }

    private void showSuccess(String message) {
        Notification.show(message, 3000, Notification.Position.MIDDLE)
                .addThemeVariants(NotificationVariant.LUMO_SUCCESS);
    }

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

    private String url(String value) {
        return URLEncoder.encode(value, StandardCharsets.UTF_8);
    }

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

    private Long toLong(Object value) {
        if (value instanceof Number number) {
            return number.longValue();
        }
        if (value instanceof String string && !string.isBlank()) {
            try {
                return Long.parseLong(string);
            } catch (NumberFormatException ignored) {
                return null;
            }
        }
        return null;
    }

    private Integer toInteger(Object value) {
        if (value instanceof Number number) {
            return number.intValue();
        }
        if (value instanceof String string && !string.isBlank()) {
            try {
                return Integer.parseInt(string);
            } catch (NumberFormatException ignored) {
                return null;
            }
        }
        return null;
    }

    private record CategoryRow(Long id,
                               String mnemonic,
                               String description,
                               Long templateId,
                               String templateName,
                               long fieldCount) {
    }

    private record FieldRow(Long id, String type, String name) {
    }

    private record TemplateRow(Long id, String name, String content, long usageCount) {
    }

    private record CategoryFieldRow(Long assignmentId, Long fieldId, String fieldName, String fieldType, int sort) {
    }

    private record TemplateOption(Long id, String label) {
    }

    private record FieldOption(Long id, String name, String type) {
        private String label() {
            return name + (type == null || type.isBlank() ? "" : " [" + type + "]");
        }
    }
}
