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.datepicker.DatePicker;
import com.vaadin.flow.component.formlayout.FormLayout;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.html.Anchor;
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 com.vaadin.flow.server.StreamResource;
import de.votian.web.model.SessionData;
import de.votian.web.service.RestClientService;
import org.springframework.core.ParameterizedTypeReference;

import java.io.ByteArrayInputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

@Route(value = "reports", layout = MainLayout.class)
@PageTitle("Votian - Berichte")
public class ReportWorkspaceView extends VerticalLayout {

    private final RestClientService restClient;
    private final SessionData sessionData;

    private final ComboBox<ObjectTypeOption> objectTypeField = new ComboBox<>("Bereich");
    private final TextField objectSearchField = new TextField("Objektsuche");
    private final Button objectSearchButton = new Button("Suchen");
    private final ComboBox<ObjectOption> objectField = new ComboBox<>("Objekt");
    private final DatePicker fromDate = new DatePicker("Von");
    private final DatePicker toDate = new DatePicker("Bis");

    private final ComboBox<ReportTypeOption> historyReportTypeField = new ComboBox<>("Berichtstyp");
    private final TextField historySearchField = new TextField("Textsuche");
    private final Button historyLoadButton = new Button("Historie laden");
    private final Anchor historyExportLink = new Anchor();
    private final Button historyExportButton = new Button("CSV exportieren");

    private final Grid<ReportRow> historyGrid = new Grid<>(ReportRow.class, false);
    private final ComboBox<ReportTypeOption> editorReportTypeField = new ComboBox<>("Berichtstyp");
    private final Checkbox editorConfidentialField = new Checkbox("Vertraulich");
    private final TextArea editorTextField = new TextArea("Berichtstext");
    private final Button editorNewButton = new Button("Neu");
    private final Button editorSaveButton = new Button("Speichern");
    private final Button editorDeleteButton = new Button("Loeschen");

    private final Checkbox splitByReportTypeField = new Checkbox("Nach Berichtstyp aufteilen");
    private final Checkbox splitByCustomerTypeField = new Checkbox("Nach Kundentyp aufteilen");
    private final Button statisticLoadButton = new Button("Statistik laden");
    private final Anchor statisticExportLink = new Anchor();
    private final Button statisticExportButton = new Button("CSV exportieren");
    private final Grid<StatisticRow> statisticGrid = new Grid<>(StatisticRow.class, false);

    private final List<ObjectTypeOption> objectTypes = new ArrayList<>();
    private final List<ObjectOption> objectOptions = new ArrayList<>();
    private final List<ReportTypeOption> historyTypeOptions = new ArrayList<>();
    private final List<ReportTypeOption> editorTypeOptions = new ArrayList<>();
    private final List<ReportRow> historyRows = new ArrayList<>();

    private Long selectedReportId;
    private boolean selectedReportEditable;
    private boolean selectedReportDeletable;

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

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

        configureFilters();
        configureHistoryGrid();
        configureStatisticGrid();
        configureEditor();
        configureExportLinks();

        Tab historyTab = new Tab("Historie");
        Tab statisticsTab = new Tab("Statistik");
        Tabs tabs = new Tabs(historyTab, statisticsTab);

        VerticalLayout historyContent = buildHistoryContent();
        VerticalLayout statisticContent = buildStatisticContent();
        statisticContent.setVisible(false);

        tabs.addSelectedChangeListener(event -> {
            historyContent.setVisible(event.getSelectedTab() == historyTab);
            statisticContent.setVisible(event.getSelectedTab() == statisticsTab);
        });

        add(new H3("Berichtsarbeitsbereich"), buildObjectFilterBar(), tabs, historyContent, statisticContent);
        expand(historyContent, statisticContent);

        loadBootstrap();
    }

    private void configureFilters() {
        objectTypeField.setItemLabelGenerator(ObjectTypeOption::label);
        objectTypeField.setWidth("220px");
        objectTypeField.addValueChangeListener(event -> {
            clearObjectSelection();
            clearEditor();
            loadReportTypes();
            updateSplitCustomerTypeState();
        });

        objectSearchField.setWidth("260px");
        objectSearchField.setClearButtonVisible(true);
        objectSearchButton.addClickListener(event -> searchObjects());

        objectField.setItemLabelGenerator(ObjectOption::labelWithSecondary);
        objectField.setWidth("420px");
        objectField.addValueChangeListener(event -> updateExportLinks());

        fromDate.setValue(LocalDate.now().withDayOfMonth(1));
        toDate.setValue(LocalDate.now());
        fromDate.addValueChangeListener(event -> updateExportLinks());
        toDate.addValueChangeListener(event -> updateExportLinks());

        historyReportTypeField.setItemLabelGenerator(ReportTypeOption::label);
        historyReportTypeField.setWidth("260px");
        historyReportTypeField.addValueChangeListener(event -> updateExportLinks());
        editorReportTypeField.setItemLabelGenerator(ReportTypeOption::label);
        editorReportTypeField.setWidthFull();

        historySearchField.setWidth("260px");
        historySearchField.setClearButtonVisible(true);
        historySearchField.addValueChangeListener(event -> updateExportLinks());
        historyLoadButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        historyLoadButton.addClickListener(event -> loadHistory());

        splitByReportTypeField.setValue(true);
        splitByCustomerTypeField.setValue(false);
        splitByReportTypeField.addValueChangeListener(event -> updateExportLinks());
        splitByCustomerTypeField.addValueChangeListener(event -> updateExportLinks());
        statisticLoadButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        statisticLoadButton.addClickListener(event -> loadStatistics());
    }

    private void configureHistoryGrid() {
        historyGrid.addColumn(ReportRow::createdAt).setHeader("Zeitpunkt").setAutoWidth(true).setFrozen(true);
        historyGrid.addColumn(ReportRow::objectLabel).setHeader("Objekt").setFlexGrow(1);
        historyGrid.addColumn(ReportRow::reportTypeLabel).setHeader("Berichtstyp").setAutoWidth(true);
        historyGrid.addColumn(ReportRow::authorName).setHeader("Mitarbeiter").setAutoWidth(true);
        historyGrid.addColumn(row -> row.confidential() ? "Ja" : "").setHeader("Vertraulich").setAutoWidth(true);
        historyGrid.addColumn(ReportRow::text).setHeader("Eintrag").setFlexGrow(2);
        historyGrid.setSizeFull();
        historyGrid.asSingleSelect().addValueChangeListener(event -> fillEditor(event.getValue()));
    }

    private void configureStatisticGrid() {
        statisticGrid.addColumn(StatisticRow::headquartersName).setHeader("Zentrale").setAutoWidth(true).setFrozen(true);
        statisticGrid.addColumn(StatisticRow::authorFirstname).setHeader("Vorname").setAutoWidth(true);
        statisticGrid.addColumn(StatisticRow::authorName).setHeader("Name").setAutoWidth(true);
        statisticGrid.addColumn(StatisticRow::reportTypeLabel).setHeader("Berichtstyp").setAutoWidth(true);
        statisticGrid.addColumn(StatisticRow::companyTypeLabel).setHeader("Kundentyp").setAutoWidth(true);
        statisticGrid.addColumn(StatisticRow::reports).setHeader("Berichte").setAutoWidth(true);
        statisticGrid.setSizeFull();
    }

    private void configureEditor() {
        editorSaveButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        editorDeleteButton.addThemeVariants(ButtonVariant.LUMO_ERROR);
        editorTextField.setWidthFull();
        editorTextField.setMinHeight("180px");

        editorNewButton.addClickListener(event -> clearEditor());
        editorSaveButton.addClickListener(event -> saveReport());
        editorDeleteButton.addClickListener(event -> deleteReport());
        refreshEditorButtons();
    }

    private void configureExportLinks() {
        historyExportLink.add(historyExportButton);
        statisticExportLink.add(statisticExportButton);
        historyExportLink.getElement().setAttribute("download", true);
        statisticExportLink.getElement().setAttribute("download", true);
        updateExportLinks();
    }

    private HorizontalLayout buildObjectFilterBar() {
        HorizontalLayout bar = new HorizontalLayout(
                objectTypeField,
                objectSearchField,
                objectSearchButton,
                objectField,
                fromDate,
                toDate
        );
        bar.setAlignItems(Alignment.BASELINE);
        return bar;
    }

    private VerticalLayout buildHistoryContent() {
        HorizontalLayout filters = new HorizontalLayout(historyReportTypeField, historySearchField, historyLoadButton, historyExportLink);
        filters.setAlignItems(Alignment.BASELINE);

        FormLayout editorForm = new FormLayout();
        editorForm.setResponsiveSteps(
                new FormLayout.ResponsiveStep("0", 1),
                new FormLayout.ResponsiveStep("900px", 2)
        );
        editorForm.add(editorReportTypeField, editorConfidentialField, editorTextField);
        editorForm.setColspan(editorTextField, 2);

        HorizontalLayout actions = new HorizontalLayout(editorNewButton, editorSaveButton, editorDeleteButton);

        VerticalLayout content = new VerticalLayout(
                new Paragraph("Historie und CRUD arbeiten direkt auf `phoenix_group.report_process`. Vertrauliche Berichte folgen der Legacy-Sichtbarkeit."),
                filters,
                historyGrid,
                new H4("Eintrag bearbeiten"),
                editorForm,
                actions
        );
        content.setPadding(false);
        content.setSpacing(true);
        content.setSizeFull();
        content.expand(historyGrid);
        return content;
    }

    private VerticalLayout buildStatisticContent() {
        HorizontalLayout controls = new HorizontalLayout(
                splitByReportTypeField,
                splitByCustomerTypeField,
                statisticLoadButton,
                statisticExportLink
        );
        controls.setAlignItems(Alignment.CENTER);

        VerticalLayout content = new VerticalLayout(
                new Paragraph("Die Statistik gruppiert die Berichte nach Mitarbeiter und optional nach Berichtstyp sowie Kundentyp."),
                controls,
                statisticGrid
        );
        content.setPadding(false);
        content.setSpacing(true);
        content.setSizeFull();
        content.expand(statisticGrid);
        return content;
    }

    private void loadBootstrap() {
        Long headquartersId = sessionData.getHeadquartersId();
        if (headquartersId == null) {
            return;
        }
        try {
            @SuppressWarnings("unchecked")
            Map<String, Object> bootstrap = restClient.get(
                    "/report-workspace/bootstrap?hqId=" + headquartersId,
                    LinkedHashMap.class
            );
            objectTypes.clear();
            Object raw = bootstrap.get("objectTypes");
            if (raw instanceof List<?> list) {
                for (Object item : list) {
                    if (item instanceof Map<?, ?> row) {
                        objectTypes.add(new ObjectTypeOption(
                                str(row.get("code")),
                                str(row.get("label"))
                        ));
                    }
                }
            }
            objectTypeField.setItems(objectTypes);
            if (!objectTypes.isEmpty()) {
                objectTypeField.setValue(objectTypes.get(0));
            }
            updateSplitCustomerTypeState();
            loadReportTypes();
        } catch (Exception e) {
            showError("Berichtsworkspace konnte nicht initialisiert werden: " + e.getMessage());
        }
    }

    private void loadReportTypes() {
        ObjectTypeOption objectType = objectTypeField.getValue();
        Long headquartersId = sessionData.getHeadquartersId();
        if (objectType == null || headquartersId == null) {
            historyReportTypeField.setItems(List.of());
            editorReportTypeField.setItems(List.of());
            return;
        }
        try {
            List<LinkedHashMap<String, Object>> result = restClient.getList(
                    "/report-workspace/report-types?hqId=" + headquartersId + "&objectType=" + objectType.code(),
                    new ParameterizedTypeReference<>() {}
            );
            historyTypeOptions.clear();
            editorTypeOptions.clear();
            historyTypeOptions.add(new ReportTypeOption(0, "Alle"));
            editorTypeOptions.add(new ReportTypeOption(0, "(ohne Typ)"));
            for (Map<String, Object> row : result) {
                Integer id = toInteger(row.get("id"));
                if (id == null) {
                    continue;
                }
                String label = str(row.get("label"));
                historyTypeOptions.add(new ReportTypeOption(id, label));
                editorTypeOptions.add(new ReportTypeOption(id, label));
            }
            historyReportTypeField.setItems(historyTypeOptions);
            editorReportTypeField.setItems(editorTypeOptions);
            historyReportTypeField.setValue(historyTypeOptions.get(0));
            editorReportTypeField.setValue(editorTypeOptions.get(0));
            updateExportLinks();
        } catch (Exception e) {
            showError("Berichtstypen konnten nicht geladen werden: " + e.getMessage());
        }
    }

    private void searchObjects() {
        ObjectTypeOption objectType = objectTypeField.getValue();
        Long headquartersId = sessionData.getHeadquartersId();
        if (objectType == null || headquartersId == null) {
            return;
        }
        try {
            String path = "/report-workspace/search?hqId=" + headquartersId
                    + "&objectType=" + objectType.code()
                    + "&query=" + url(objectSearchField.getValue());
            List<LinkedHashMap<String, Object>> result = restClient.getList(path, new ParameterizedTypeReference<>() {});
            objectOptions.clear();
            for (Map<String, Object> row : result) {
                Long id = toLong(row.get("id"));
                if (id == null) {
                    continue;
                }
                objectOptions.add(new ObjectOption(
                        id,
                        str(row.get("label")),
                        str(row.get("secondaryLabel"))
                ));
            }
            objectField.setItems(objectOptions);
            if (!objectOptions.isEmpty()) {
                objectField.setValue(objectOptions.get(0));
            }
            updateExportLinks();
        } catch (Exception e) {
            showError("Objekte konnten nicht gesucht werden: " + e.getMessage());
        }
    }

    private void loadHistory() {
        ObjectTypeOption objectType = objectTypeField.getValue();
        Long headquartersId = sessionData.getHeadquartersId();
        if (objectType == null || headquartersId == null) {
            return;
        }
        try {
            StringBuilder path = new StringBuilder("/report-workspace/reports?hqId=")
                    .append(headquartersId)
                    .append("&objectType=").append(objectType.code());
            if (objectField.getValue() != null) {
                path.append("&objectId=").append(objectField.getValue().id());
            }
            if (fromDate.getValue() != null) {
                path.append("&from=").append(fromDate.getValue());
            }
            if (toDate.getValue() != null) {
                path.append("&to=").append(toDate.getValue());
            }
            if (historyReportTypeField.getValue() != null && historyReportTypeField.getValue().id() != null
                    && historyReportTypeField.getValue().id() > 0) {
                path.append("&reportType=").append(historyReportTypeField.getValue().id());
            }
            if (!historySearchField.getValue().isBlank()) {
                path.append("&search=").append(url(historySearchField.getValue()));
            }
            List<LinkedHashMap<String, Object>> result = restClient.getList(path.toString(), new ParameterizedTypeReference<>() {});
            historyRows.clear();
            for (Map<String, Object> row : result) {
                Long id = toLong(row.get("id"));
                if (id == null) {
                    continue;
                }
                historyRows.add(new ReportRow(
                        id,
                        str(row.get("objectType")),
                        toLong(row.get("objectId")),
                        str(row.get("objectLabel")),
                        str(row.get("headquartersName")),
                        toLong(row.get("authorUserId")),
                        str(row.get("authorName")),
                        str(row.get("authorPhone")),
                        str(row.get("createdAt")).replace("T", " "),
                        toInteger(row.get("reportType")),
                        str(row.get("reportTypeLabel")),
                        str(row.get("text")),
                        Boolean.TRUE.equals(row.get("confidential")) || "true".equalsIgnoreCase(str(row.get("confidential"))),
                        Boolean.TRUE.equals(row.get("editable")) || "true".equalsIgnoreCase(str(row.get("editable"))),
                        Boolean.TRUE.equals(row.get("deletable")) || "true".equalsIgnoreCase(str(row.get("deletable")))
                ));
            }
            historyGrid.setItems(historyRows);
            historyGrid.asSingleSelect().clear();
            clearEditor();
            updateExportLinks();
        } catch (Exception e) {
            showError("Historie konnte nicht geladen werden: " + e.getMessage());
        }
    }

    private void loadStatistics() {
        ObjectTypeOption objectType = objectTypeField.getValue();
        Long headquartersId = sessionData.getHeadquartersId();
        if (objectType == null || headquartersId == null) {
            return;
        }
        try {
            StringBuilder path = new StringBuilder("/report-workspace/statistics?hqId=")
                    .append(headquartersId)
                    .append("&objectType=").append(objectType.code())
                    .append("&splitByReportType=").append(splitByReportTypeField.getValue())
                    .append("&splitByCustomerType=").append(splitByCustomerTypeField.getValue());
            if (fromDate.getValue() != null) {
                path.append("&from=").append(fromDate.getValue());
            }
            if (toDate.getValue() != null) {
                path.append("&to=").append(toDate.getValue());
            }
            List<LinkedHashMap<String, Object>> result = restClient.getList(path.toString(), new ParameterizedTypeReference<>() {});
            List<StatisticRow> rows = new ArrayList<>();
            for (Map<String, Object> row : result) {
                rows.add(new StatisticRow(
                        str(row.get("headquartersName")),
                        str(row.get("authorFirstname")),
                        str(row.get("authorName")),
                        str(row.get("reportTypeLabel")),
                        str(row.get("companyTypeLabel")),
                        toLong(row.get("reports")) != null ? toLong(row.get("reports")) : 0L
                ));
            }
            statisticGrid.setItems(rows);
            updateExportLinks();
        } catch (Exception e) {
            showError("Statistik konnte nicht geladen werden: " + e.getMessage());
        }
    }

    private void saveReport() {
        ObjectTypeOption objectType = objectTypeField.getValue();
        ObjectOption object = objectField.getValue();
        Long headquartersId = sessionData.getHeadquartersId();
        if (objectType == null || object == null || headquartersId == null) {
            showError("Bitte zuerst Bereich und Objekt waehlen.");
            return;
        }
        try {
            Map<String, Object> request = new LinkedHashMap<>();
            request.put("hqId", headquartersId);
            request.put("objectType", objectType.code());
            request.put("objectId", object.id());
            request.put("reportType", editorReportTypeField.getValue() != null ? editorReportTypeField.getValue().id() : 0);
            request.put("text", editorTextField.getValue());
            request.put("confidential", editorConfidentialField.getValue());

            if (selectedReportId == null) {
                restClient.post("/report-workspace/reports", request, LinkedHashMap.class);
            } else {
                restClient.put("/report-workspace/reports/" + selectedReportId, request);
            }
            showSuccess("Bericht gespeichert.");
            loadHistory();
        } catch (Exception e) {
            showError("Bericht konnte nicht gespeichert werden: " + e.getMessage());
        }
    }

    private void deleteReport() {
        Long headquartersId = sessionData.getHeadquartersId();
        if (selectedReportId == null || headquartersId == null || !selectedReportDeletable) {
            return;
        }
        try {
            restClient.delete("/report-workspace/reports/" + selectedReportId + "?hqId=" + headquartersId);
            showSuccess("Bericht geloescht.");
            loadHistory();
        } catch (Exception e) {
            showError("Bericht konnte nicht geloescht werden: " + e.getMessage());
        }
    }

    private void fillEditor(ReportRow row) {
        if (row == null) {
            clearEditor();
            return;
        }
        selectedReportId = row.id();
        selectedReportEditable = row.editable();
        selectedReportDeletable = row.deletable();
        editorTextField.setValue(row.text());
        editorConfidentialField.setValue(row.confidential());
        editorReportTypeField.setValue(editorTypeOptions.stream()
                .filter(option -> Objects.equals(option.id(), row.reportType()))
                .findFirst()
                .orElse(editorTypeOptions.isEmpty() ? null : editorTypeOptions.get(0)));

        if (row.objectId() != null) {
            ObjectOption reportObject = new ObjectOption(row.objectId(), row.objectLabel(), "");
            if (objectOptions.stream().noneMatch(option -> Objects.equals(option.id(), reportObject.id()))) {
                objectOptions.add(0, reportObject);
                objectField.setItems(objectOptions);
            }
            objectField.setValue(objectOptions.stream()
                    .filter(option -> Objects.equals(option.id(), reportObject.id()))
                    .findFirst()
                    .orElse(reportObject));
        }
        refreshEditorButtons();
    }

    private void clearEditor() {
        selectedReportId = null;
        selectedReportEditable = true;
        selectedReportDeletable = false;
        historyGrid.asSingleSelect().clear();
        editorTextField.clear();
        editorConfidentialField.clear();
        if (!editorTypeOptions.isEmpty()) {
            editorReportTypeField.setValue(editorTypeOptions.get(0));
        } else {
            editorReportTypeField.clear();
        }
        refreshEditorButtons();
    }

    private void clearObjectSelection() {
        objectOptions.clear();
        objectField.clear();
        objectField.setItems(List.of());
        updateExportLinks();
    }

    private void updateSplitCustomerTypeState() {
        boolean customerMode = objectTypeField.getValue() != null && "cs".equals(objectTypeField.getValue().code());
        splitByCustomerTypeField.setEnabled(customerMode);
        if (!customerMode) {
            splitByCustomerTypeField.setValue(false);
        }
    }

    private void refreshEditorButtons() {
        editorSaveButton.setEnabled(selectedReportId == null || selectedReportEditable);
        editorDeleteButton.setEnabled(selectedReportId != null && selectedReportDeletable);
    }

    private void updateExportLinks() {
        boolean historyEnabled = objectTypeField.getValue() != null && sessionData.canManageReports();
        boolean statisticEnabled = objectTypeField.getValue() != null && sessionData.canManageReports();
        historyExportButton.setEnabled(historyEnabled);
        statisticExportButton.setEnabled(statisticEnabled);
        if (historyEnabled) {
            historyExportLink.setHref(historyExportResource());
        } else {
            historyExportLink.setHref("");
        }
        if (statisticEnabled) {
            statisticExportLink.setHref(statisticExportResource());
        } else {
            statisticExportLink.setHref("");
        }
    }

    private StreamResource historyExportResource() {
        String filename = "berichte_" + objectTypeField.getValue().code() + ".csv";
        return new StreamResource(filename, () -> new ByteArrayInputStream(restClient.getBytes(buildHistoryExportPath())));
    }

    private StreamResource statisticExportResource() {
        String filename = "berichtsstatistik_" + objectTypeField.getValue().code() + ".csv";
        return new StreamResource(filename, () -> new ByteArrayInputStream(restClient.getBytes(buildStatisticExportPath())));
    }

    private String buildHistoryExportPath() {
        StringBuilder path = new StringBuilder("/report-workspace/export/history?hqId=")
                .append(sessionData.getHeadquartersId())
                .append("&objectType=").append(objectTypeField.getValue().code());
        if (objectField.getValue() != null) {
            path.append("&objectId=").append(objectField.getValue().id());
        }
        if (fromDate.getValue() != null) {
            path.append("&from=").append(fromDate.getValue());
        }
        if (toDate.getValue() != null) {
            path.append("&to=").append(toDate.getValue());
        }
        if (historyReportTypeField.getValue() != null && historyReportTypeField.getValue().id() != null
                && historyReportTypeField.getValue().id() > 0) {
            path.append("&reportType=").append(historyReportTypeField.getValue().id());
        }
        if (!historySearchField.getValue().isBlank()) {
            path.append("&search=").append(url(historySearchField.getValue()));
        }
        return path.toString();
    }

    private String buildStatisticExportPath() {
        StringBuilder path = new StringBuilder("/report-workspace/export/statistics?hqId=")
                .append(sessionData.getHeadquartersId())
                .append("&objectType=").append(objectTypeField.getValue().code())
                .append("&splitByReportType=").append(splitByReportTypeField.getValue())
                .append("&splitByCustomerType=").append(splitByCustomerTypeField.getValue());
        if (fromDate.getValue() != null) {
            path.append("&from=").append(fromDate.getValue());
        }
        if (toDate.getValue() != null) {
            path.append("&to=").append(toDate.getValue());
        }
        return path.toString();
    }

    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 != null ? 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 ObjectTypeOption(String code, String label) {
    }

    private record ObjectOption(Long id, String label, String secondaryLabel) {
        private String labelWithSecondary() {
            if (secondaryLabel == null || secondaryLabel.isBlank()) {
                return label;
            }
            return label + " [" + secondaryLabel + "]";
        }
    }

    private record ReportTypeOption(Integer id, String label) {
    }

    private record ReportRow(Long id,
                             String objectType,
                             Long objectId,
                             String objectLabel,
                             String headquartersName,
                             Long authorUserId,
                             String authorName,
                             String authorPhone,
                             String createdAt,
                             Integer reportType,
                             String reportTypeLabel,
                             String text,
                             boolean confidential,
                             boolean editable,
                             boolean deletable) {
    }

    private record StatisticRow(String headquartersName,
                                String authorFirstname,
                                String authorName,
                                String reportTypeLabel,
                                String companyTypeLabel,
                                long reports) {
    }
}
