package de.votian.web.view;

import com.vaadin.flow.component.Component;
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.checkbox.CheckboxGroup;
import com.vaadin.flow.component.combobox.ComboBox;
import com.vaadin.flow.component.datepicker.DatePicker;
import com.vaadin.flow.component.datetimepicker.DateTimePicker;
import com.vaadin.flow.component.dialog.Dialog;
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.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

@Route(value = "communication", layout = MainLayout.class)
@PageTitle("Votian - Kommunikation")
public class CommunicationWorkspaceView extends VerticalLayout {

    private final RestClientService restClient;
    private final SessionData sessionData;

    private final Paragraph infoLine = new Paragraph();

    private final ComboBox<TickerTargetMode> tickerTargetModeField = new ComboBox<>("Ziel");
    private final ComboBox<EmployeeOption> tickerEmployeeField = new ComboBox<>("Mitarbeiter");
    private final DateTimePicker tickerStartField = new DateTimePicker("Start");
    private final DateTimePicker tickerEndField = new DateTimePicker("Ende");
    private final Checkbox tickerUnerasableField = new Checkbox("Nicht automatisch entfernen");
    private final TextArea tickerTextField = new TextArea("Mitteilung");
    private final Button tickerSaveButton = new Button("Mitteilung einstellen");
    private final Grid<TickerRow> tickerGrid = new Grid<>(TickerRow.class, false);

    private final Grid<MessageGroupRow> groupGrid = new Grid<>(MessageGroupRow.class, false);
    private final TextField groupNameField = new TextField("Gruppenname");
    private final Button groupNewButton = new Button("Neu");
    private final Button groupSaveButton = new Button("Speichern");
    private final Button groupDeleteButton = new Button("Loeschen");
    private final Grid<GroupAssignmentRow> assignmentGrid = new Grid<>(GroupAssignmentRow.class, false);
    private final Grid<CourierOption> courierGrid = new Grid<>(CourierOption.class, false);
    private final TextField courierSearchField = new TextField("Kuriersuche");
    private final Button courierLoadButton = new Button("Kuriere laden");
    private final CheckboxGroup<MessageGroupOption> courierGroupSelection = new CheckboxGroup<>("Nachrichtengruppen");
    private final Button courierGroupSaveButton = new Button("Zuordnung speichern");

    private final DatePicker messageFromField = new DatePicker("Von");
    private final DatePicker messageToField = new DatePicker("Bis");
    private final ComboBox<MessageTypeOption> messageTypeField = new ComboBox<>("Typ");
    private final CheckboxGroup<MessageStateOption> messageStateField = new CheckboxGroup<>("Status");
    private final TextField messageSearchField = new TextField("Suche");
    private final Button messageLoadButton = new Button("Historie laden");
    private final Grid<MessageRow> messageGrid = new Grid<>(MessageRow.class, false);

    private final CheckboxGroup<MessageGroupOption> sendGroupSelection = new CheckboxGroup<>("Gruppen");
    private final ComboBox<CourierOption> sendCourierField = new ComboBox<>("Nur an Kurier");
    private final Checkbox sendAllActiveField = new Checkbox("An alle aktiven Fahrer senden");
    private final TextField sendSubjectField = new TextField("Betreff");
    private final TextArea sendBodyField = new TextArea("Text");
    private final Button sendMessageButton = new Button("Nachricht senden");

    private final ComboBox<NewsletterTypeOption> newsletterTypeField = new ComboBox<>("Typ");
    private final ComboBox<NewsletterStatusOption> newsletterStatusField = new ComboBox<>("Status");
    private final TextField newsletterSearchField = new TextField("Suche");
    private final Button newsletterLoadButton = new Button("Empfaenger laden");
    private final Grid<NewsletterRecipientRow> newsletterGrid = new Grid<>(NewsletterRecipientRow.class, false);
    private final TextField newsletterRecipientField = new TextField("Objekt");
    private final TextField newsletterCompanyField = new TextField("Firma");
    private final TextField newsletterEmailField = new TextField("E-Mail");
    private final Checkbox newsletterActiveField = new Checkbox("Newsletter aktiv");
    private final Checkbox newsletterDsgvoField = new Checkbox("DSGVO bestaetigt");
    private final Button newsletterSaveButton = new Button("Status speichern");

    private final List<EmployeeOption> employees = new ArrayList<>();
    private final List<MessageGroupOption> messageGroupOptions = new ArrayList<>();
    private final List<CourierOption> couriers = new ArrayList<>();

    private Long selectedGroupId;
    private Long selectedCourierId;
    private String selectedNewsletterType;
    private Long selectedNewsletterRecipientId;

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

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

        configureTickerTab();
        configureGroupsTab();
        configureMessagesTab();
        configureNewsletterTab();

        LinkedHashMap<Tab, VerticalLayout> contents = new LinkedHashMap<>();
        if (sessionData.canManageTicker()) {
            contents.put(new Tab("Mitteilungen"), buildTickerContent());
        }
        if (sessionData.canManageCourierMessageGroups()) {
            contents.put(new Tab("Gruppen"), buildGroupContent());
        }
        if (sessionData.canManageDeviceMessages()) {
            contents.put(new Tab("Nachrichten"), buildMessageContent());
        }
        if (sessionData.canManageNewsletter()) {
            contents.put(new Tab("Newsletter"), buildNewsletterContent());
        }

        Tabs tabs = new Tabs(contents.keySet().toArray(Tab[]::new));
        boolean first = true;
        for (VerticalLayout content : contents.values()) {
            content.setVisible(first);
            first = false;
        }
        tabs.addSelectedChangeListener(event ->
                contents.forEach((tab, content) -> content.setVisible(tab.equals(event.getSelectedTab()))));

        add(new H3("Kommunikationsworkspace"), infoLine, tabs);
        contents.values().forEach(this::add);
        if (!contents.isEmpty()) {
            expand(contents.values().toArray(Component[]::new));
        }

        loadBootstrap();
    }

    private void configureTickerTab() {
        tickerTargetModeField.setItems(
                new TickerTargetMode("global", "Global"),
                new TickerTargetMode("headquarters", "Diese Niederlassung"),
                new TickerTargetMode("employee", "Einzelner Mitarbeiter")
        );
        tickerTargetModeField.setItemLabelGenerator(TickerTargetMode::label);
        tickerTargetModeField.setValue(new TickerTargetMode("headquarters", "Diese Niederlassung"));
        tickerTargetModeField.addValueChangeListener(event -> tickerEmployeeField.setEnabled("employee".equals(modeCode())));

        tickerEmployeeField.setItemLabelGenerator(EmployeeOption::label);
        tickerEmployeeField.setWidth("320px");
        tickerEmployeeField.setEnabled(false);

        tickerStartField.setValue(LocalDateTime.now());
        tickerEndField.setValue(LocalDateTime.now().plusDays(1));
        tickerTextField.setWidthFull();
        tickerTextField.setMinHeight("140px");

        tickerSaveButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        tickerSaveButton.addClickListener(event -> saveTicker());

        tickerGrid.addColumn(TickerRow::createdAt).setHeader("Erstellt").setAutoWidth(true).setFrozen(true);
        tickerGrid.addColumn(TickerRow::startAt).setHeader("Von").setAutoWidth(true);
        tickerGrid.addColumn(TickerRow::endAt).setHeader("Bis").setAutoWidth(true);
        tickerGrid.addColumn(TickerRow::creatorLabel).setHeader("Absender").setAutoWidth(true);
        tickerGrid.addColumn(TickerRow::targetLabel).setHeader("Ziel").setAutoWidth(true);
        tickerGrid.addColumn(TickerRow::text).setHeader("Mitteilung").setFlexGrow(1);
        tickerGrid.addComponentColumn(row -> {
            Button delete = new Button("Entfernen");
            delete.addThemeVariants(ButtonVariant.LUMO_TERTIARY, ButtonVariant.LUMO_ERROR);
            delete.setEnabled(row.deletable());
            delete.addClickListener(event -> deleteTicker(row));
            return delete;
        }).setHeader("Aktion").setAutoWidth(true);
        tickerGrid.setSizeFull();
    }

    private void configureGroupsTab() {
        groupGrid.addColumn(MessageGroupRow::name).setHeader("Gruppe").setFlexGrow(1).setFrozen(true);
        groupGrid.addColumn(MessageGroupRow::courierCount).setHeader("Kuriere").setAutoWidth(true);
        groupGrid.setHeight("220px");
        groupGrid.asSingleSelect().addValueChangeListener(event -> fillGroupForm(event.getValue()));

        groupSaveButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        groupDeleteButton.addThemeVariants(ButtonVariant.LUMO_ERROR);
        groupNewButton.addClickListener(event -> clearGroupForm());
        groupSaveButton.addClickListener(event -> saveGroup());
        groupDeleteButton.addClickListener(event -> deleteGroup());

        assignmentGrid.addColumn(GroupAssignmentRow::groupName).setHeader("Gruppe").setAutoWidth(true).setFrozen(true);
        assignmentGrid.addColumn(GroupAssignmentRow::courierCode).setHeader("EID").setAutoWidth(true);
        assignmentGrid.addColumn(GroupAssignmentRow::courierName).setHeader("Kurier").setFlexGrow(1);
        assignmentGrid.setHeight("220px");

        courierSearchField.setClearButtonVisible(true);
        courierLoadButton.addClickListener(event -> loadCouriers());

        courierGrid.addColumn(CourierOption::code).setHeader("EID").setAutoWidth(true).setFrozen(true);
        courierGrid.addColumn(CourierOption::sid).setHeader("SID").setAutoWidth(true);
        courierGrid.addColumn(CourierOption::company).setHeader("Firma").setFlexGrow(1);
        courierGrid.addColumn(CourierOption::contactName).setHeader("Kontakt").setAutoWidth(true);
        courierGrid.setHeight("260px");
        courierGrid.asSingleSelect().addValueChangeListener(event -> fillCourierGroups(event.getValue()));

        courierGroupSelection.setItemLabelGenerator(MessageGroupOption::label);
        courierGroupSaveButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        courierGroupSaveButton.addClickListener(event -> saveCourierGroups());
    }

    private void configureMessagesTab() {
        messageFromField.setValue(LocalDate.now());
        messageToField.setValue(LocalDate.now());

        messageTypeField.setItems(
                new MessageTypeOption("all", "Alle"),
                new MessageTypeOption("direct", "Nur direkte"),
                new MessageTypeOption("group", "Nur Gruppen")
        );
        messageTypeField.setItemLabelGenerator(MessageTypeOption::label);
        messageTypeField.setValue(new MessageTypeOption("all", "Alle"));

        messageStateField.setItemLabelGenerator(MessageStateOption::label);
        messageStateField.setItems(
                new MessageStateOption(0, "Neu"),
                new MessageStateOption(1, "Ausgeliefert"),
                new MessageStateOption(2, "Gelesen"),
                new MessageStateOption(3, "Beantwortet")
        );
        messageStateField.select(new MessageStateOption(0, "Neu"), new MessageStateOption(1, "Ausgeliefert"), new MessageStateOption(2, "Gelesen"), new MessageStateOption(3, "Beantwortet"));

        messageSearchField.setClearButtonVisible(true);
        messageLoadButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        messageLoadButton.addClickListener(event -> loadMessages());

        messageGrid.addColumn(MessageRow::createdAt).setHeader("Zeitpunkt").setAutoWidth(true).setFrozen(true);
        messageGrid.addColumn(MessageRow::stateLabel).setHeader("Status").setAutoWidth(true);
        messageGrid.addColumn(MessageRow::senderLabel).setHeader("Sender").setAutoWidth(true);
        messageGrid.addColumn(MessageRow::receiverLabel).setHeader("Empfaenger").setAutoWidth(true);
        messageGrid.addColumn(MessageRow::subject).setHeader("Betreff").setAutoWidth(true);
        messageGrid.addColumn(MessageRow::body).setHeader("Text").setFlexGrow(1);
        messageGrid.addComponentColumn(row -> {
            HorizontalLayout actions = new HorizontalLayout();
            if (row.readable()) {
                Button read = new Button("Gelesen");
                read.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
                read.addClickListener(event -> markRead(row));
                actions.add(read);
            }
            if (row.answerable()) {
                Button answer = new Button("Antworten");
                answer.addThemeVariants(ButtonVariant.LUMO_TERTIARY, ButtonVariant.LUMO_PRIMARY);
                answer.addClickListener(event -> answer(row));
                actions.add(answer);
            }
            return actions;
        }).setHeader("Aktionen").setAutoWidth(true);
        messageGrid.setSizeFull();

        sendGroupSelection.setItemLabelGenerator(MessageGroupOption::label);
        sendCourierField.setItemLabelGenerator(CourierOption::label);
        sendCourierField.setWidth("320px");
        sendAllActiveField.addValueChangeListener(event -> {
            boolean allActive = Boolean.TRUE.equals(event.getValue());
            sendCourierField.setEnabled(!allActive);
            sendGroupSelection.setEnabled(!allActive);
        });
        sendBodyField.setWidthFull();
        sendBodyField.setMinHeight("120px");

        sendMessageButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        sendMessageButton.addClickListener(event -> sendMessage());
    }

    private void configureNewsletterTab() {
        newsletterTypeField.setItems(
                new NewsletterTypeOption("all", "Alle"),
                new NewsletterTypeOption("cs", "Kunden"),
                new NewsletterTypeOption("cr", "Kuriere")
        );
        newsletterTypeField.setItemLabelGenerator(NewsletterTypeOption::label);
        newsletterTypeField.setValue(new NewsletterTypeOption("all", "Alle"));

        newsletterStatusField.setItems(
                new NewsletterStatusOption("all", "Alle"),
                new NewsletterStatusOption("ready", "Versandbereit"),
                new NewsletterStatusOption("active", "Nur aktiv"),
                new NewsletterStatusOption("inactive", "Nur abgemeldet"),
                new NewsletterStatusOption("pendingConsent", "DSGVO offen"),
                new NewsletterStatusOption("missingEmail", "Ohne E-Mail")
        );
        newsletterStatusField.setItemLabelGenerator(NewsletterStatusOption::label);
        newsletterStatusField.setValue(new NewsletterStatusOption("ready", "Versandbereit"));

        newsletterSearchField.setClearButtonVisible(true);
        newsletterLoadButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        newsletterLoadButton.addClickListener(event -> loadNewsletterRecipients());

        newsletterGrid.addColumn(NewsletterRecipientRow::recipientTypeLabel).setHeader("Typ").setAutoWidth(true).setFrozen(true);
        newsletterGrid.addColumn(NewsletterRecipientRow::codeLabel).setHeader("Kennung").setAutoWidth(true);
        newsletterGrid.addColumn(NewsletterRecipientRow::companyName).setHeader("Firma").setFlexGrow(1);
        newsletterGrid.addColumn(NewsletterRecipientRow::contactName).setHeader("Kontakt").setAutoWidth(true);
        newsletterGrid.addColumn(NewsletterRecipientRow::email).setHeader("E-Mail").setFlexGrow(1);
        newsletterGrid.addColumn(row -> row.newsletterActive() ? "Ja" : "Nein").setHeader("Opt-in").setAutoWidth(true);
        newsletterGrid.addColumn(row -> row.dsgvoConfirmed() ? "Ja" : "Nein").setHeader("DSGVO").setAutoWidth(true);
        newsletterGrid.addColumn(row -> row.deliverable() ? "Ja" : "Nein").setHeader("Versand").setAutoWidth(true);
        newsletterGrid.asSingleSelect().addValueChangeListener(event -> fillNewsletterForm(event.getValue()));
        newsletterGrid.setSizeFull();

        newsletterRecipientField.setReadOnly(true);
        newsletterCompanyField.setReadOnly(true);
        newsletterEmailField.setReadOnly(true);
        newsletterSaveButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        newsletterSaveButton.setEnabled(false);
        newsletterSaveButton.addClickListener(event -> saveNewsletterRecipient());
    }

    private VerticalLayout buildTickerContent() {
        FormLayout form = new FormLayout();
        form.setResponsiveSteps(
                new FormLayout.ResponsiveStep("0", 1),
                new FormLayout.ResponsiveStep("900px", 3)
        );
        form.add(tickerTargetModeField, tickerEmployeeField, tickerUnerasableField, tickerStartField, tickerEndField, tickerTextField);
        form.setColspan(tickerTextField, 3);

        VerticalLayout layout = new VerticalLayout(
                new Paragraph("Mitteilungen arbeiten direkt auf `phoenix_group.tickerforum` und folgen der Legacy-Sichtbarkeit fuer Ersteller, Empfaenger, Zentrale und globale Meldungen."),
                form,
                tickerSaveButton,
                tickerGrid
        );
        layout.setPadding(false);
        layout.setSpacing(true);
        layout.setSizeFull();
        return layout;
    }

    private VerticalLayout buildGroupContent() {
        HorizontalLayout groupActions = new HorizontalLayout(groupNewButton, groupSaveButton, groupDeleteButton);
        groupActions.setAlignItems(Alignment.BASELINE);

        HorizontalLayout courierControls = new HorizontalLayout(courierSearchField, courierLoadButton);
        courierControls.setAlignItems(Alignment.BASELINE);

        VerticalLayout layout = new VerticalLayout(
                new Paragraph("Nachrichtengruppen und Kurierzuordnungen bleiben in `messagegroup` bzw. `courier.cr_msggrp`. Die Matrix darunter entspricht der alten Zuordnungsliste."),
                new H4("Gruppen"),
                groupGrid,
                groupNameField,
                groupActions,
                new H4("Aktuelle Zuordnungen"),
                assignmentGrid,
                new H4("Kuriergruppen pflegen"),
                courierControls,
                courierGrid,
                courierGroupSelection,
                courierGroupSaveButton
        );
        layout.setPadding(false);
        layout.setSpacing(true);
        layout.setSizeFull();
        return layout;
    }

    private VerticalLayout buildMessageContent() {
        HorizontalLayout filters = new HorizontalLayout(messageFromField, messageToField, messageTypeField, messageSearchField, messageLoadButton);
        filters.setAlignItems(Alignment.BASELINE);

        FormLayout sendForm = new FormLayout();
        sendForm.setResponsiveSteps(
                new FormLayout.ResponsiveStep("0", 1),
                new FormLayout.ResponsiveStep("900px", 2)
        );
        sendForm.add(sendGroupSelection, sendCourierField, sendAllActiveField, sendSubjectField, sendBodyField);
        sendForm.setColspan(sendBodyField, 2);

        VerticalLayout layout = new VerticalLayout(
                new Paragraph("Der Nachrichtenbereich pflegt `phoenix_log.messageforum` inkl. Lesen, Antworten und Versand an Gruppen, einzelne Fahrer oder aktive Fahrer."),
                filters,
                messageStateField,
                messageGrid,
                new H4("Neue Nachricht"),
                sendForm,
                sendMessageButton
        );
        layout.setPadding(false);
        layout.setSpacing(true);
        layout.setSizeFull();
        return layout;
    }

    private VerticalLayout buildNewsletterContent() {
        HorizontalLayout filters = new HorizontalLayout(newsletterTypeField, newsletterStatusField, newsletterSearchField, newsletterLoadButton);
        filters.setAlignItems(Alignment.BASELINE);

        FormLayout editor = new FormLayout();
        editor.setResponsiveSteps(
                new FormLayout.ResponsiveStep("0", 1),
                new FormLayout.ResponsiveStep("900px", 2)
        );
        editor.add(newsletterRecipientField, newsletterCompanyField, newsletterEmailField, newsletterActiveField, newsletterDsgvoField);
        editor.setColspan(newsletterRecipientField, 2);
        editor.setColspan(newsletterCompanyField, 2);
        editor.setColspan(newsletterEmailField, 2);

        VerticalLayout layout = new VerticalLayout(
                new Paragraph("Der Newsletter-Bereich ersetzt die verstreute Pflege von `cmp_newsletter` und `cmp_dsgvo` fuer Kunden- und Kurierfirmen. Versandbereit ist nur, was Opt-in, DSGVO und E-Mail-Adresse zusammen erfuellt."),
                filters,
                newsletterGrid,
                new H4("Ausgewaehlten Empfaenger pflegen"),
                editor,
                newsletterSaveButton
        );
        layout.setPadding(false);
        layout.setSpacing(true);
        layout.setSizeFull();
        return layout;
    }

    private void loadBootstrap() {
        Long headquartersId = sessionData.getHeadquartersId();
        if (headquartersId == null) {
            return;
        }
        try {
            @SuppressWarnings("unchecked")
            Map<String, Object> bootstrap = restClient.get(
                    "/communication-workspace/bootstrap?hqId=" + headquartersId,
                    LinkedHashMap.class
            );
            Integer unread = toInteger(bootstrap.get("unreadCourierMessagesToday"));
            infoLine.setText("Offene Fahrernachrichten heute: " + (unread != null ? unread : 0));
            if (sessionData.canManageTicker()) {
                loadEmployees();
                loadTickers();
            }
            if (sessionData.canManageCourierMessageGroups() || sessionData.canManageDeviceMessages()) {
                loadMessageGroups();
                loadCouriers();
            }
            if (sessionData.canManageCourierMessageGroups()) {
                loadAssignments();
            }
            if (sessionData.canManageDeviceMessages()) {
                loadMessages();
            }
            if (sessionData.canManageNewsletter()) {
                loadNewsletterRecipients();
            }
        } catch (Exception e) {
            showError("Kommunikationsworkspace konnte nicht initialisiert werden: " + e.getMessage());
        }
    }

    private void loadEmployees() {
        Long headquartersId = sessionData.getHeadquartersId();
        if (headquartersId == null) {
            return;
        }
        try {
            List<LinkedHashMap<String, Object>> result = restClient.getList(
                    "/communication-workspace/employees?hqId=" + headquartersId,
                    new ParameterizedTypeReference<>() {}
            );
            employees.clear();
            for (Map<String, Object> row : result) {
                Long id = toLong(row.get("id"));
                if (id != null) {
                    employees.add(new EmployeeOption(id, str(row.get("label"))));
                }
            }
            tickerEmployeeField.setItems(employees);
        } catch (Exception e) {
            showError("Mitarbeiter konnten nicht geladen werden: " + e.getMessage());
        }
    }

    private void loadMessageGroups() {
        Long headquartersId = sessionData.getHeadquartersId();
        if (headquartersId == null) {
            return;
        }
        try {
            List<LinkedHashMap<String, Object>> result = restClient.getList(
                    "/communication-workspace/groups?hqId=" + headquartersId,
                    new ParameterizedTypeReference<>() {}
            );
            List<MessageGroupRow> rows = new ArrayList<>();
            messageGroupOptions.clear();
            for (Map<String, Object> row : result) {
                Long id = toLong(row.get("id"));
                if (id == null) {
                    continue;
                }
                String name = str(row.get("name"));
                Integer courierCount = toInteger(row.get("courierCount"));
                rows.add(new MessageGroupRow(id, name, courierCount != null ? courierCount : 0));
                messageGroupOptions.add(new MessageGroupOption(id, name));
            }
            groupGrid.setItems(rows);
            courierGroupSelection.setItems(messageGroupOptions);
            sendGroupSelection.setItems(messageGroupOptions);
        } catch (Exception e) {
            showError("Nachrichtengruppen konnten nicht geladen werden: " + e.getMessage());
        }
    }

    private void loadAssignments() {
        Long headquartersId = sessionData.getHeadquartersId();
        if (headquartersId == null) {
            return;
        }
        try {
            List<LinkedHashMap<String, Object>> result = restClient.getList(
                    "/communication-workspace/assignments?hqId=" + headquartersId,
                    new ParameterizedTypeReference<>() {}
            );
            List<GroupAssignmentRow> rows = new ArrayList<>();
            for (Map<String, Object> row : result) {
                Long groupId = toLong(row.get("groupId"));
                Long courierId = toLong(row.get("courierId"));
                if (groupId == null || courierId == null) {
                    continue;
                }
                rows.add(new GroupAssignmentRow(
                        groupId,
                        str(row.get("groupName")),
                        courierId,
                        str(row.get("courierCode")),
                        str(row.get("courierName"))
                ));
            }
            assignmentGrid.setItems(rows);
        } catch (Exception e) {
            showError("Zuordnungen konnten nicht geladen werden: " + e.getMessage());
        }
    }

    private void loadCouriers() {
        Long headquartersId = sessionData.getHeadquartersId();
        if (headquartersId == null) {
            return;
        }
        try {
            String path = "/communication-workspace/couriers?hqId=" + headquartersId
                    + "&query=" + url(courierSearchField.getValue());
            List<LinkedHashMap<String, Object>> result = restClient.getList(path, new ParameterizedTypeReference<>() {});
            couriers.clear();
            for (Map<String, Object> row : result) {
                Long id = toLong(row.get("id"));
                if (id == null) {
                    continue;
                }
                couriers.add(new CourierOption(
                        id,
                        str(row.get("code")),
                        str(row.get("sid")),
                        str(row.get("company")),
                        str(row.get("contactName")),
                        toLongList(row.get("groupIds"))
                ));
            }
            courierGrid.setItems(couriers);
            sendCourierField.setItems(couriers);
        } catch (Exception e) {
            showError("Kuriere konnten nicht geladen werden: " + e.getMessage());
        }
    }

    private void loadTickers() {
        Long headquartersId = sessionData.getHeadquartersId();
        if (headquartersId == null) {
            return;
        }
        try {
            List<LinkedHashMap<String, Object>> result = restClient.getList(
                    "/communication-workspace/tickers?hqId=" + headquartersId,
                    new ParameterizedTypeReference<>() {}
            );
            List<TickerRow> rows = new ArrayList<>();
            for (Map<String, Object> row : result) {
                Long id = toLong(row.get("id"));
                if (id == null) {
                    continue;
                }
                String headquartersLabel = str(row.get("targetHeadquartersLabel"));
                String employeeLabel = str(row.get("targetEmployeeLabel"));
                String targetLabel = !employeeLabel.isBlank()
                        ? employeeLabel
                        : (!headquartersLabel.isBlank() ? headquartersLabel : "Global");
                rows.add(new TickerRow(
                        id,
                        str(row.get("createdAt")),
                        str(row.get("startAt")),
                        str(row.get("endAt")),
                        str(row.get("text")),
                        str(row.get("creatorLabel")),
                        targetLabel,
                        Boolean.TRUE.equals(row.get("deletable"))
                ));
            }
            tickerGrid.setItems(rows);
        } catch (Exception e) {
            showError("Mitteilungen konnten nicht geladen werden: " + e.getMessage());
        }
    }

    private void loadMessages() {
        Long headquartersId = sessionData.getHeadquartersId();
        if (headquartersId == null) {
            return;
        }
        try {
            StringBuilder path = new StringBuilder("/communication-workspace/messages?hqId=")
                    .append(headquartersId)
                    .append("&from=").append(messageFromField.getValue())
                    .append("&to=").append(messageToField.getValue())
                    .append("&type=").append(messageTypeField.getValue() != null ? messageTypeField.getValue().code() : "all")
                    .append("&search=").append(url(messageSearchField.getValue()));
            for (MessageStateOption option : messageStateField.getSelectedItems()) {
                path.append("&states=").append(option.id());
            }
            List<LinkedHashMap<String, Object>> result = restClient.getList(path.toString(), new ParameterizedTypeReference<>() {});
            List<MessageRow> rows = new ArrayList<>();
            for (Map<String, Object> row : result) {
                Long id = toLong(row.get("id"));
                if (id == null) {
                    continue;
                }
                Integer state = toInteger(row.get("state"));
                rows.add(new MessageRow(
                        id,
                        str(row.get("createdAt")),
                        state != null ? state : 0,
                        str(row.get("senderLabel")),
                        str(row.get("receiverLabel")),
                        str(row.get("subject")),
                        str(row.get("body")),
                        Boolean.TRUE.equals(row.get("readable")),
                        Boolean.TRUE.equals(row.get("answerable"))
                ));
            }
            messageGrid.setItems(rows);
        } catch (Exception e) {
            showError("Nachrichten konnten nicht geladen werden: " + e.getMessage());
        }
    }

    private void loadNewsletterRecipients() {
        Long headquartersId = sessionData.getHeadquartersId();
        if (headquartersId == null) {
            return;
        }
        try {
            String path = "/communication-workspace/newsletter?hqId=" + headquartersId
                    + "&type=" + (newsletterTypeField.getValue() != null ? newsletterTypeField.getValue().code() : "all")
                    + "&status=" + (newsletterStatusField.getValue() != null ? newsletterStatusField.getValue().code() : "all")
                    + "&search=" + url(newsletterSearchField.getValue());
            List<LinkedHashMap<String, Object>> result = restClient.getList(path, new ParameterizedTypeReference<>() {});
            List<NewsletterRecipientRow> rows = new ArrayList<>();
            for (Map<String, Object> row : result) {
                String recipientType = str(row.get("recipientType"));
                Long recipientId = toLong(row.get("recipientId"));
                Long companyId = toLong(row.get("companyId"));
                if (recipientType.isBlank() || recipientId == null || companyId == null) {
                    continue;
                }
                rows.add(new NewsletterRecipientRow(
                        recipientType,
                        recipientId,
                        companyId,
                        str(row.get("recipientTypeLabel")),
                        str(row.get("recipientCode")),
                        str(row.get("secondaryCode")),
                        str(row.get("companyName")),
                        str(row.get("contactName")),
                        str(row.get("email")),
                        Boolean.TRUE.equals(row.get("newsletterActive")),
                        Boolean.TRUE.equals(row.get("dsgvoConfirmed")),
                        Boolean.TRUE.equals(row.get("deliverable"))
                ));
            }
            newsletterGrid.setItems(rows);
            if (selectedNewsletterRecipientId != null && selectedNewsletterType != null) {
                rows.stream()
                        .filter(row -> row.recipientType().equals(selectedNewsletterType))
                        .filter(row -> row.recipientId().equals(selectedNewsletterRecipientId))
                        .findFirst()
                        .ifPresentOrElse(newsletterGrid::select, this::clearNewsletterForm);
            }
        } catch (Exception e) {
            showError("Newsletter-Empfaenger konnten nicht geladen werden: " + e.getMessage());
        }
    }

    private void saveTicker() {
        Long headquartersId = sessionData.getHeadquartersId();
        if (headquartersId == null) {
            return;
        }
        try {
            Map<String, Object> body = new LinkedHashMap<>();
            body.put("hqId", headquartersId);
            body.put("text", tickerTextField.getValue());
            body.put("startAt", tickerStartField.getValue());
            body.put("endAt", tickerEndField.getValue());
            body.put("unerasable", tickerUnerasableField.getValue());
            if ("headquarters".equals(modeCode())) {
                body.put("targetHeadquartersId", headquartersId);
            } else if ("employee".equals(modeCode()) && tickerEmployeeField.getValue() != null) {
                body.put("targetEmployeeId", tickerEmployeeField.getValue().id());
            } else {
                body.put("targetHeadquartersId", 0);
            }
            restClient.post("/communication-workspace/tickers", body, LinkedHashMap.class);
            tickerTextField.clear();
            loadTickers();
            showInfo("Mitteilung eingestellt.");
        } catch (Exception e) {
            showError("Mitteilung konnte nicht gespeichert werden: " + e.getMessage());
        }
    }

    private void deleteTicker(TickerRow row) {
        Long headquartersId = sessionData.getHeadquartersId();
        if (headquartersId == null) {
            return;
        }
        try {
            restClient.delete("/communication-workspace/tickers/" + row.id() + "?hqId=" + headquartersId);
            loadTickers();
            showInfo("Mitteilung entfernt.");
        } catch (Exception e) {
            showError("Mitteilung konnte nicht entfernt werden: " + e.getMessage());
        }
    }

    private void fillGroupForm(MessageGroupRow row) {
        if (row == null) {
            clearGroupForm();
            return;
        }
        selectedGroupId = row.id();
        groupNameField.setValue(row.name());
    }

    private void clearGroupForm() {
        selectedGroupId = null;
        groupGrid.deselectAll();
        groupNameField.clear();
    }

    private void saveGroup() {
        Long headquartersId = sessionData.getHeadquartersId();
        if (headquartersId == null) {
            return;
        }
        try {
            Map<String, Object> body = Map.of(
                    "hqId", headquartersId,
                    "name", groupNameField.getValue()
            );
            if (selectedGroupId != null) {
                restClient.put("/communication-workspace/groups/" + selectedGroupId, body);
            } else {
                restClient.post("/communication-workspace/groups", body, LinkedHashMap.class);
            }
            clearGroupForm();
            loadMessageGroups();
            loadAssignments();
            loadCouriers();
            showInfo("Nachrichtengruppe gespeichert.");
        } catch (Exception e) {
            showError("Nachrichtengruppe konnte nicht gespeichert werden: " + e.getMessage());
        }
    }

    private void deleteGroup() {
        Long headquartersId = sessionData.getHeadquartersId();
        if (selectedGroupId == null || headquartersId == null) {
            return;
        }
        try {
            restClient.delete("/communication-workspace/groups/" + selectedGroupId + "?hqId=" + headquartersId);
            clearGroupForm();
            loadMessageGroups();
            loadAssignments();
            loadCouriers();
            showInfo("Nachrichtengruppe geloescht.");
        } catch (Exception e) {
            showError("Nachrichtengruppe konnte nicht geloescht werden: " + e.getMessage());
        }
    }

    private void fillCourierGroups(CourierOption row) {
        if (row == null) {
            selectedCourierId = null;
            courierGroupSelection.clear();
            return;
        }
        selectedCourierId = row.id();
        Set<MessageGroupOption> selected = new LinkedHashSet<>();
        for (MessageGroupOption option : messageGroupOptions) {
            if (row.groupIds().contains(option.id())) {
                selected.add(option);
            }
        }
        courierGroupSelection.setValue(selected);
    }

    private void fillNewsletterForm(NewsletterRecipientRow row) {
        if (row == null) {
            clearNewsletterForm();
            return;
        }
        selectedNewsletterType = row.recipientType();
        selectedNewsletterRecipientId = row.recipientId();
        newsletterRecipientField.setValue(row.recipientTypeLabel() + " " + row.codeLabel());
        newsletterCompanyField.setValue(row.companyName());
        newsletterEmailField.setValue(row.email());
        newsletterActiveField.setValue(row.newsletterActive());
        newsletterDsgvoField.setValue(row.dsgvoConfirmed());
        newsletterSaveButton.setEnabled(true);
    }

    private void clearNewsletterForm() {
        selectedNewsletterType = null;
        selectedNewsletterRecipientId = null;
        newsletterGrid.deselectAll();
        newsletterRecipientField.clear();
        newsletterCompanyField.clear();
        newsletterEmailField.clear();
        newsletterActiveField.setValue(false);
        newsletterDsgvoField.setValue(false);
        newsletterSaveButton.setEnabled(false);
    }

    private void saveCourierGroups() {
        Long headquartersId = sessionData.getHeadquartersId();
        if (selectedCourierId == null || headquartersId == null) {
            return;
        }
        try {
            Map<String, Object> body = new LinkedHashMap<>();
            body.put("hqId", headquartersId);
            body.put("groupIds", courierGroupSelection.getSelectedItems().stream().map(MessageGroupOption::id).toList());
            restClient.put("/communication-workspace/couriers/" + selectedCourierId + "/groups", body);
            loadAssignments();
            loadCouriers();
            showInfo("Kurierzuordnung gespeichert.");
        } catch (Exception e) {
            showError("Kurierzuordnung konnte nicht gespeichert werden: " + e.getMessage());
        }
    }

    private void saveNewsletterRecipient() {
        Long headquartersId = sessionData.getHeadquartersId();
        if (headquartersId == null || selectedNewsletterType == null || selectedNewsletterRecipientId == null) {
            return;
        }
        try {
            Map<String, Object> body = new LinkedHashMap<>();
            body.put("hqId", headquartersId);
            body.put("newsletterActive", newsletterActiveField.getValue());
            body.put("dsgvoConfirmed", newsletterDsgvoField.getValue());
            restClient.put("/communication-workspace/newsletter/" + selectedNewsletterType + "/" + selectedNewsletterRecipientId, body);
            loadNewsletterRecipients();
            showInfo("Newsletter-Status gespeichert.");
        } catch (Exception e) {
            showError("Newsletter-Status konnte nicht gespeichert werden: " + e.getMessage());
        }
    }

    private void markRead(MessageRow row) {
        Long headquartersId = sessionData.getHeadquartersId();
        if (headquartersId == null) {
            return;
        }
        try {
            restClient.post("/communication-workspace/messages/" + row.id() + "/read?hqId=" + headquartersId, Map.of(), LinkedHashMap.class);
            loadMessages();
            showInfo("Nachricht als gelesen markiert.");
        } catch (Exception e) {
            showError("Nachricht konnte nicht markiert werden: " + e.getMessage());
        }
    }

    private void answer(MessageRow row) {
        Dialog dialog = new Dialog();
        dialog.setHeaderTitle("Antwort auf Nachricht " + row.id());
        TextField subjectField = new TextField("Betreff");
        subjectField.setWidthFull();
        TextArea bodyField = new TextArea("Text");
        bodyField.setWidthFull();
        bodyField.setMinHeight("140px");
        Button sendButton = new Button("Antwort senden");
        sendButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        sendButton.addClickListener(event -> {
            try {
                Map<String, Object> body = Map.of(
                        "hqId", sessionData.getHeadquartersId(),
                        "subject", subjectField.getValue(),
                        "body", bodyField.getValue()
                );
                restClient.post("/communication-workspace/messages/" + row.id() + "/answer", body, LinkedHashMap.class);
                dialog.close();
                loadMessages();
                showInfo("Antwort versendet.");
            } catch (Exception e) {
                showError("Antwort konnte nicht versendet werden: " + e.getMessage());
            }
        });
        VerticalLayout layout = new VerticalLayout(subjectField, bodyField, sendButton);
        layout.setPadding(false);
        layout.setSpacing(true);
        dialog.add(layout);
        dialog.open();
    }

    private void sendMessage() {
        Long headquartersId = sessionData.getHeadquartersId();
        if (headquartersId == null) {
            return;
        }
        try {
            Map<String, Object> body = new LinkedHashMap<>();
            body.put("hqId", headquartersId);
            body.put("groupIds", sendGroupSelection.getSelectedItems().stream().map(MessageGroupOption::id).toList());
            body.put("courierSid", sendCourierField.getValue() != null ? sendCourierField.getValue().sid() : "");
            body.put("subject", sendSubjectField.getValue());
            body.put("body", sendBodyField.getValue());
            body.put("allActiveCouriers", sendAllActiveField.getValue());
            @SuppressWarnings("unchecked")
            Map<String, Object> result = restClient.post("/communication-workspace/send", body, LinkedHashMap.class);
            Integer recipients = toInteger(result.get("recipients"));
            sendSubjectField.clear();
            sendBodyField.clear();
            sendGroupSelection.clear();
            sendCourierField.clear();
            sendAllActiveField.setValue(false);
            loadMessages();
            showInfo("Nachricht versendet an " + (recipients != null ? recipients : 0) + " Empfaenger.");
        } catch (Exception e) {
            showError("Nachricht konnte nicht versendet werden: " + e.getMessage());
        }
    }

    private String modeCode() {
        return tickerTargetModeField.getValue() != null ? tickerTargetModeField.getValue().code() : "headquarters";
    }

    private void showInfo(String message) {
        Notification notification = Notification.show(message, 3000, Notification.Position.TOP_END);
        notification.addThemeVariants(NotificationVariant.LUMO_SUCCESS);
    }

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

    private static String url(String value) {
        return URLEncoder.encode(value != null ? value : "", java.nio.charset.StandardCharsets.UTF_8);
    }

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

    private static Long toLong(Object value) {
        if (value instanceof Number number) {
            return number.longValue();
        }
        if (value != null && !String.valueOf(value).isBlank()) {
            return Long.parseLong(String.valueOf(value));
        }
        return null;
    }

    private static Integer toInteger(Object value) {
        if (value instanceof Number number) {
            return number.intValue();
        }
        if (value != null && !String.valueOf(value).isBlank()) {
            return Integer.parseInt(String.valueOf(value));
        }
        return null;
    }

    private static List<Long> toLongList(Object value) {
        List<Long> result = new ArrayList<>();
        if (value instanceof List<?> list) {
            for (Object item : list) {
                Long longValue = toLong(item);
                if (longValue != null) {
                    result.add(longValue);
                }
            }
        }
        return result;
    }

    private record TickerTargetMode(String code, String label) {
    }

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

    private record TickerRow(Long id,
                             String createdAt,
                             String startAt,
                             String endAt,
                             String text,
                             String creatorLabel,
                             String targetLabel,
                             boolean deletable) {
    }

    private record MessageGroupRow(Long id, String name, int courierCount) {
    }

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

    private record GroupAssignmentRow(Long groupId, String groupName, Long courierId, String courierCode, String courierName) {
    }

    private record CourierOption(Long id,
                                 String code,
                                 String sid,
                                 String company,
                                 String contactName,
                                 List<Long> groupIds) {
        private String label() {
            return code + (sid.isBlank() ? "" : " [" + sid + "]") + (company.isBlank() ? "" : " :: " + company);
        }
    }

    private record MessageTypeOption(String code, String label) {
    }

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

    private record NewsletterTypeOption(String code, String label) {
    }

    private record NewsletterStatusOption(String code, String label) {
    }

    private record NewsletterRecipientRow(String recipientType,
                                          Long recipientId,
                                          Long companyId,
                                          String recipientTypeLabel,
                                          String recipientCode,
                                          String secondaryCode,
                                          String companyName,
                                          String contactName,
                                          String email,
                                          boolean newsletterActive,
                                          boolean dsgvoConfirmed,
                                          boolean deliverable) {
        private String codeLabel() {
            return secondaryCode.isBlank() ? recipientCode : recipientCode + " [" + secondaryCode + "]";
        }
    }

    private record MessageRow(Long id,
                              String createdAt,
                              int state,
                              String senderLabel,
                              String receiverLabel,
                              String subject,
                              String body,
                              boolean readable,
                              boolean answerable) {
        private String stateLabel() {
            return switch (state) {
                case 0 -> "Neu";
                case 1 -> "Ausgeliefert";
                case 2 -> "Gelesen";
                case 3 -> "Beantwortet";
                default -> String.valueOf(state);
            };
        }
    }
}
