package de.assecutor.votianlt.pages.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.confirmdialog.ConfirmDialog;
import com.vaadin.flow.component.dialog.Dialog;

import com.vaadin.flow.component.datepicker.DatePicker;
import com.vaadin.flow.component.html.H2;
import com.vaadin.flow.component.timepicker.TimePicker;
import com.vaadin.flow.component.html.H3;
import com.vaadin.flow.component.html.Main;
import com.vaadin.flow.component.html.Span;
import com.vaadin.flow.component.icon.Icon;
import com.vaadin.flow.component.icon.VaadinIcon;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.orderedlayout.FlexComponent;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.component.textfield.IntegerField;
import com.vaadin.flow.component.textfield.NumberField;
import com.vaadin.flow.data.binder.Binder;
import com.vaadin.flow.router.Menu;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.textfield.TextArea;
import com.vaadin.flow.component.tabs.TabSheet;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.theme.lumo.LumoUtility;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import de.assecutor.votianlt.model.Job;
import de.assecutor.votianlt.model.task.BaseTask;
import de.assecutor.votianlt.model.task.TaskType;
import de.assecutor.votianlt.model.task.ConfirmationTask;
import de.assecutor.votianlt.model.task.SignatureTask;
import de.assecutor.votianlt.model.task.TodoListTask;
import de.assecutor.votianlt.model.task.PhotoTask;
import de.assecutor.votianlt.model.task.BarcodeTask;
import de.assecutor.votianlt.model.task.CommentTask;
import de.assecutor.votianlt.pages.service.AddJobService;
import de.assecutor.votianlt.pages.service.CustomerService;
import de.assecutor.votianlt.pages.service.AddCustomerService;
import de.assecutor.votianlt.pages.service.AddressValidationService;
import de.assecutor.votianlt.model.Customer;
import de.assecutor.votianlt.pages.service.AppUserService;
import de.assecutor.votianlt.model.AppUser;
import de.assecutor.votianlt.pages.service.TaskTemplateService;
import de.assecutor.votianlt.model.TaskTemplate;
import de.assecutor.votianlt.model.User;
import de.assecutor.votianlt.security.SecurityService;
import de.assecutor.votianlt.model.Service;
import de.assecutor.votianlt.repository.ServiceRepository;
import com.vaadin.flow.component.grid.Grid;
import java.math.BigDecimal;
import java.math.RoundingMode;

import jakarta.annotation.security.RolesAllowed;
import lombok.extern.slf4j.Slf4j;
import de.assecutor.votianlt.model.CargoItem;
import de.assecutor.votianlt.model.AddressValidationResult;
import de.assecutor.votianlt.model.RouteCalculationResult;
import java.time.LocalDate;
import java.util.*;
import java.util.Objects;
import java.util.Optional;

@Route(value = "add_job", layout = de.assecutor.votianlt.pages.base.ui.view.MainLayout.class)
@PageTitle("Neuen Auftrag anlegen")
@Menu(order = 0, icon = "vaadin:clipboard-check", title = "Auftragserstellung")
@RolesAllowed("USER")
@Slf4j
public class AddJobView extends Main {

    private final AddJobService addJobService;
    private final CustomerService customerService;
    private final AddCustomerService addCustomerService;
    private final AppUserService appUserService;
    private final TaskTemplateService taskTemplateService;
    private final SecurityService securityService;
    private final ServiceRepository serviceRepository;
    private final AddressValidationService addressValidationService;

    // Customer selection
    private ComboBox<String> customerSelection;
    private Button preloadAddressButton;

    // Pickup address fields
    private ComboBox<String> pickupCompany;
    private ComboBox<String> pickupSalutation;
    private TextField pickupFirstName;
    private TextField pickupLastName;
    private TextField pickupPhone;
    private TextField pickupStreet;
    private TextField pickupHouseNumber;
    private TextField pickupAddressAddition;
    private TextField pickupZip;
    private TextField pickupCity;
    private Checkbox savePickupAddress;

    // Delivery address fields
    private ComboBox<String> deliveryCompany;
    private ComboBox<String> deliverySalutation;
    private TextField deliveryFirstName;
    private TextField deliveryLastName;
    private TextField deliveryPhone;
    private TextField deliveryStreet;
    private TextField deliveryHouseNumber;
    private TextField deliveryAddressAddition;
    private TextField deliveryZip;
    private TextField deliveryCity;
    private Checkbox saveDeliveryAddress;

    // Digital processing
    private Checkbox digitalProcessing;
    private ComboBox<AppUser> appUser;

    // Services for the job
    private Grid<Service> servicesGrid;
    private final List<Service> selectedServices = new ArrayList<>();
    private Span netTotalLabel;
    private Span vatTotalLabel;
    private Span grossTotalLabel;

    // Route distance display
    private VerticalLayout routeInfoBox;
    private Span routeDistanceLabel;
    private Span routeDurationLabel;
    
    // Manuelle Eingabe für Route (wenn keine Berechnung erfolgt)
    private VerticalLayout manualRouteInputBox;
    private com.vaadin.flow.component.textfield.NumberField manualDistanceInput;
    private com.vaadin.flow.component.textfield.IntegerField manualDurationInput;

    // Date picker fields for appointments
    private DatePicker pickupDate;
    private DatePicker deliveryDate;

    // Time picker fields for appointments
    private TimePicker pickupTime;
    private TimePicker deliveryTime;

    private com.vaadin.flow.component.tabs.Tab addressesTab;
    private com.vaadin.flow.component.tabs.Tab appointmentsTab;
    private com.vaadin.flow.component.tabs.Tab cargoTab;
    private com.vaadin.flow.component.tabs.Tab tasksTab;
    private com.vaadin.flow.component.tabs.Tab priceTab;

    // Submit button
    private Button submitButton;

    // Backing list for cargo items to mirror UI rows
    private final List<CargoItem> cargoItemsState = new ArrayList<>();
    // Stage sections for drag and drop
    // Backing list for tasks to mirror UI rows
    private final List<BaseTask> tasksState = new ArrayList<>();
    // Dynamic lists and additional controls
    // Cargo section UI refs for error highlighting
    private VerticalLayout cargoAreaContainer;
    private Span cargoError;
    private VerticalLayout cargoList;
    private VerticalLayout tasksList;
    private ComboBox<TaskTemplate> templateComboBox;
    private TextArea remarkArea;
    private VerticalLayout pickupSection;
    private VerticalLayout deliverySection;

    private final Binder<Job> binder = new Binder<>(Job.class);

    // Mapping für die Anzeige-Labels der Kunden zur Entität
    private final Map<String, Customer> customerLabelToEntity = new LinkedHashMap<>();

    // Available app users for the current user
    private List<AppUser> availableAppUsers;

    // Adressvalidierung
    private final Map<String, AddressValidationResult> addressValidationResults = new HashMap<>();
    private RouteCalculationResult routeCalculationResult;
    private boolean addressesDirty = true; // true = Adressen müssen validiert werden
    private boolean validationDialogOpen = false; // true = Dialog ist gerade geöffnet
    private TabSheet tabSheet;

    public AddJobView(AddJobService addJobService, AddCustomerService addCustomerService,
            CustomerService customerService, AppUserService appUserService, TaskTemplateService taskTemplateService,
            SecurityService securityService, ServiceRepository serviceRepository,
            AddressValidationService addressValidationService) {
        this.addJobService = addJobService;
        this.addCustomerService = addCustomerService;
        this.customerService = customerService;
        this.appUserService = appUserService;
        this.taskTemplateService = taskTemplateService;
        this.securityService = securityService;
        this.serviceRepository = serviceRepository;
        this.addressValidationService = addressValidationService;
        initializeComponents();
        setupLayout();
        setupValidation();
        loadDraftIfExists();
        loadMandatoryServices();
    }

    private void initializeComponents() {
        // Customer selection
        customerSelection = new ComboBox<>("Auftraggeber/Rechnungsempfänger");
        customerSelection.setPlaceholder("Wählen Sie einen Auftraggeber aus...");
        customerSelection.setWidthFull();
        customerSelection.setRequiredIndicatorVisible(true);
        // Mit Kunden des angemeldeten Benutzers befüllen und Mapping aufbauen
        List<Customer> ownerCustomers = customerService.findAllForCurrentOwner();
        customerLabelToEntity.clear();
        for (Customer c : ownerCustomers) {
            String label = (c.getCompanyName() != null && !c.getCompanyName().isBlank())
                    ? c.getCompanyName() + " | "
                            + ((c.getFirstname() != null ? c.getFirstname() : "") + " "
                                    + (c.getLastName() != null ? c.getLastName() : "")).trim()
                    : ((c.getFirstname() != null ? c.getFirstname() : "") + " "
                            + (c.getLastName() != null ? c.getLastName() : "")).trim();
            if (label.isBlank()) {
                label = "Unbenannter Kunde";
            }
            // Bei Duplikaten Label einzigartig machen
            String uniqueLabel = label;
            int counter = 2;
            while (customerLabelToEntity.containsKey(uniqueLabel)) {
                uniqueLabel = label + " (" + counter++ + ")";
            }
            customerLabelToEntity.put(uniqueLabel, c);
        }
        customerSelection.setItems(new ArrayList<>(customerLabelToEntity.keySet()));

        // Bei Auswahl eines Kunden Abholfelder befüllen
        customerSelection.addValueChangeListener(ev -> {
            String selected = ev.getValue();
            if (selected == null) {
                // Wenn kein Kunde ausgewählt ist, Checkbox wieder aktivieren
                savePickupAddress.setValue(true);
                return;
            }

            // Streckeninformationen zurücksetzen, da sich die Abholadresse ändert
            resetRouteInformation();

            Customer c = customerLabelToEntity.get(selected);
            if (c == null)
                return;

            // Pickup-Checkbox deaktivieren, da Kunde bereits existiert
            savePickupAddress.setValue(false);

            // Firma
            if (c.getCompanyName() != null) {
                pickupCompany.setValue(c.getCompanyName());
            } else {
                pickupCompany.clear();
            }
            // Anrede (nur setzen, wenn vorhanden und zulässig)
            if (c.getTitle() != null && ("Herr".equalsIgnoreCase(c.getTitle()) || "Frau".equalsIgnoreCase(c.getTitle())
                    || "Divers".equalsIgnoreCase(c.getTitle()))) {
                pickupSalutation.setValue(c.getTitle());
            } else {
                pickupSalutation.clear();
            }
            // Namen
            if (c.getFirstname() != null) {
                pickupFirstName.setValue(c.getFirstname());
            } else {
                pickupFirstName.clear();
            }
            if (c.getLastName() != null) {
                pickupLastName.setValue(c.getLastName());
            } else {
                pickupLastName.clear();
            }
            // Telefon
            if (c.getTelephone() != null) {
                pickupPhone.setValue(c.getTelephone());
            } else {
                pickupPhone.clear();
            }
            // Adresse
            if (c.getStreet() != null) {
                pickupStreet.setValue(c.getStreet());
            } else {
                pickupStreet.clear();
            }
            if (c.getHouseNumber() != null) {
                pickupHouseNumber.setValue(c.getHouseNumber());
            } else {
                pickupHouseNumber.clear();
            }
            if (c.getAddressAddition() != null) {
                pickupAddressAddition.setValue(c.getAddressAddition());
            } else {
                pickupAddressAddition.clear();
            }
            if (c.getZip() != null) {
                pickupZip.setValue(c.getZip());
            } else {
                pickupZip.clear();
            }
            if (c.getCity() != null) {
                pickupCity.setValue(c.getCity());
            } else {
                pickupCity.clear();
            }
        });

        preloadAddressButton = new Button("Vorbelegte Adressfelder leeren");
        preloadAddressButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        preloadAddressButton.addClickListener(event -> clearAllFields());

        // Pickup address
        pickupCompany = new ComboBox<>("Firma");
        pickupCompany.setPlaceholder("Firmenname");
        pickupCompany.setAllowCustomValue(true);
        setupCompanyAutocomplete(pickupCompany, true); // true für Pickup
        pickupSalutation = new ComboBox<>("Anrede");
        pickupSalutation.setItems("Herr", "Frau", "Divers");
        pickupSalutation.setPlaceholder("Anrede wählen...");
        pickupFirstName = new TextField("Vorname");
        pickupFirstName.setPlaceholder("Vorname");
        pickupFirstName.setRequiredIndicatorVisible(true);
        pickupLastName = new TextField("Nachname");
        pickupLastName.setPlaceholder("Nachname");
        pickupLastName.setRequiredIndicatorVisible(true);
        pickupPhone = new TextField("Telefonnummer");
        pickupPhone.setPlaceholder("Telefonnummer");
        pickupStreet = new TextField("Straße");
        pickupStreet.setPlaceholder("Musterstraße");
        pickupStreet.setRequiredIndicatorVisible(true);
        pickupHouseNumber = new TextField("Hausnummer");
        pickupHouseNumber.setPlaceholder("Hausnummer");
        pickupHouseNumber.setRequiredIndicatorVisible(true);
        pickupAddressAddition = new TextField("Adresszusatz");
        pickupAddressAddition.setPlaceholder("2. OG, Hinterhaus...");
        pickupZip = new TextField("Postleitzahl");
        pickupZip.setPlaceholder("Postleitzahl");
        pickupZip.setRequiredIndicatorVisible(true);
        pickupCity = new TextField("Ort");
        pickupCity.setPlaceholder("Hamburg");
        pickupCity.setRequiredIndicatorVisible(true);
        savePickupAddress = new Checkbox("Die Adresse für zukünftige Aufträge speichern.");
        savePickupAddress.setValue(true);

        // Delivery address
        deliveryCompany = new ComboBox<>("Firma");
        deliveryCompany.setPlaceholder("Firmenname");
        deliveryCompany.setAllowCustomValue(true);
        setupCompanyAutocomplete(deliveryCompany, false); // false für Delivery
        deliverySalutation = new ComboBox<>("Anrede");
        deliverySalutation.setItems("Herr", "Frau", "Divers");
        deliverySalutation.setPlaceholder("Anrede wählen...");
        deliveryFirstName = new TextField("Vorname");
        deliveryFirstName.setPlaceholder("Vorname");
        deliveryFirstName.setRequiredIndicatorVisible(true);
        deliveryLastName = new TextField("Nachname");
        deliveryLastName.setPlaceholder("Nachname");
        deliveryLastName.setRequiredIndicatorVisible(true);
        deliveryPhone = new TextField("Telefonnummer");
        deliveryPhone.setPlaceholder("Telefonnummer");
        deliveryStreet = new TextField("Straße");
        deliveryStreet.setPlaceholder("Beispielweg");
        deliveryStreet.setRequiredIndicatorVisible(true);
        deliveryHouseNumber = new TextField("Hausnr");
        deliveryHouseNumber.setPlaceholder("Hausnummer");
        deliveryHouseNumber.setRequiredIndicatorVisible(true);
        deliveryAddressAddition = new TextField("Adresszusatz");
        deliveryAddressAddition.setPlaceholder("Erdgeschoss, links...");
        deliveryZip = new TextField("Postleitzahl");
        deliveryZip.setPlaceholder("Postleitzahl");
        deliveryZip.setRequiredIndicatorVisible(true);
        deliveryCity = new TextField("Ort");
        deliveryCity.setPlaceholder("Berlin");
        deliveryCity.setRequiredIndicatorVisible(true);
        saveDeliveryAddress = new Checkbox("Die Adresse für zukünftige Aufträge speichern.");
        saveDeliveryAddress.setValue(true);

        // Digital processing - set value based on user's profile setting
        digitalProcessing = new Checkbox("Digitale Abwicklung per App");
        // Get current user's digital processing preference from profile
        try {
            User currentUser = securityService.getCurrentDatabaseUser();
            digitalProcessing.setValue(currentUser.isDigitalProcessingEnabled());
        } catch (Exception e) {
            digitalProcessing.setValue(true); // Default to true if user not found
        }
        appUser = new ComboBox<>("App-Nutzer");

        // Load app users for current user and set up the ComboBox
        availableAppUsers = appUserService.findByCurrentUser();
        appUser.setItems(availableAppUsers);
        appUser.setItemLabelGenerator(
                user -> user.getVorname() + " " + user.getNachname() + " (" + user.getEmail() + ")");
        appUser.setPlaceholder("App-Nutzer auswählen...");

        // Services grid will be initialized in createPriceAndSubmitTab()
        // Date picker fields for appointments
        pickupDate = new DatePicker("Datum");
        pickupDate.setRequiredIndicatorVisible(true);
        pickupDate.setMin(LocalDate.now());
        pickupDate.setLocale(java.util.Locale.GERMANY); // Monday as first day of week
        pickupDate.setI18n(new DatePicker.DatePickerI18n().setFirstDayOfWeek(1) // 1 = Monday
                .setMonthNames(java.util.Arrays.asList("Januar", "Februar", "März", "April", "Mai", "Juni", "Juli",
                        "August", "September", "Oktober", "November", "Dezember"))
                .setWeekdays(java.util.Arrays.asList("Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag",
                        "Freitag", "Samstag"))
                .setWeekdaysShort(java.util.Arrays.asList("So", "Mo", "Di", "Mi", "Do", "Fr", "Sa")));

        deliveryDate = new DatePicker("Datum");
        deliveryDate.setRequiredIndicatorVisible(true);
        deliveryDate.setMin(LocalDate.now());
        deliveryDate.setLocale(java.util.Locale.GERMANY); // Monday as first day of week
        deliveryDate.setI18n(new DatePicker.DatePickerI18n().setFirstDayOfWeek(1) // 1 = Monday
                .setMonthNames(java.util.Arrays.asList("Januar", "Februar", "März", "April", "Mai", "Juni", "Juli",
                        "August", "September", "Oktober", "November", "Dezember"))
                .setWeekdays(java.util.Arrays.asList("Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag",
                        "Freitag", "Samstag"))
                .setWeekdaysShort(java.util.Arrays.asList("So", "Mo", "Di", "Mi", "Do", "Fr", "Sa")));

        // Submit button - initially disabled until all required fields are valid
        submitButton = new Button("Auftrag anlegen", event -> submit());
        submitButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        submitButton.setEnabled(false);

        // Listener für Adressänderungen registrieren
        setupAddressChangeListeners();
    }

    // Testdaten entfernt

    private void setupLayout() {
        setSizeFull();
        addClassNames(LumoUtility.BoxSizing.BORDER, LumoUtility.Display.FLEX, LumoUtility.FlexDirection.COLUMN,
                LumoUtility.Padding.MEDIUM, LumoUtility.Gap.SMALL);

        H2 title = new H2("Neuen Auftrag anlegen");
        add(title);

        // Create TabSheet for organizing the form
        // TabSheet and Tab references for dynamic label updates
        tabSheet = new TabSheet();
        tabSheet.setSizeFull();

        // Tab 1: Customer & Addresses
        addressesTab = tabSheet.add("Auftraggeber & Adressen", createCustomerAndAddressesTab());

        // Tab 2: Appointments & Processing
        appointmentsTab = tabSheet.add("Termine & Verarbeitung", createAppointmentsAndProcessingTab());

        // Tab 3: Cargo
        cargoTab = tabSheet.add("Ladung", createCargoTab());

        // Tab 4: Tasks
        tasksTab = tabSheet.add("Aufgaben", createTasksTab());

        // Disable tasks tab initially if digital processing is off
        if (!Boolean.TRUE.equals(digitalProcessing.getValue())) {
            tasksTab.setEnabled(false);
            tasksState.clear();
            if (tasksList != null) {
                tasksList.removeAll();
            }
        }

        // Tab 5: Price & Submit
        priceTab = tabSheet.add("Leistungen und Preis", createPriceAndSubmitTab());

        // Tab-Wechsel-Listener für Adressvalidierung
        tabSheet.addSelectedChangeListener(this::onTabChange);

        add(tabSheet);

        // Add submit button horizontally centered below the tabs
        HorizontalLayout buttonLayout = new HorizontalLayout();
        buttonLayout.setWidthFull();
        buttonLayout.setJustifyContentMode(FlexComponent.JustifyContentMode.CENTER);
        buttonLayout.setPadding(true);
        buttonLayout.add(submitButton);

        add(buttonLayout);
    }

    private Component createCustomerAndAddressesTab() {
        VerticalLayout tabContent = new VerticalLayout();
        tabContent.setSizeFull();
        tabContent.setPadding(true);
        tabContent.setSpacing(true);

        // Customer selection section
        HorizontalLayout customerLayout = new HorizontalLayout();
        customerLayout.setWidthFull();
        customerLayout.setAlignItems(FlexComponent.Alignment.END);
        customerLayout.add(customerSelection, preloadAddressButton);
        customerSelection.setWidth("70%");
        preloadAddressButton.setWidth("30%");

        tabContent.add(customerLayout);

        // Main content layout with two equal columns (50% each)
        HorizontalLayout mainLayout = new HorizontalLayout();
        mainLayout.setWidthFull();
        mainLayout.setSpacing(true);
        mainLayout.setDefaultVerticalComponentAlignment(FlexComponent.Alignment.START);

        // Left column (50%) - Pickup address section
        pickupSection = createPickupSection();
        pickupSection.setWidth("50%");

        // Right column (50%) - Delivery address section
        deliverySection = createDeliverySection();
        deliverySection.setWidth("50%");

        // Setup focus listeners for input fields
        setupInputFieldFocusListeners();

        mainLayout.add(pickupSection, deliverySection);
        tabContent.add(mainLayout);

        return tabContent;
    }

    private Component createAppointmentsAndProcessingTab() {
        VerticalLayout tabContent = new VerticalLayout();
        tabContent.setSizeFull();
        tabContent.setPadding(true);
        tabContent.setSpacing(true);
        tabContent.setDefaultHorizontalComponentAlignment(FlexComponent.Alignment.CENTER);

        // Container with fixed width to center content
        VerticalLayout content = new VerticalLayout();
        content.setPadding(false);
        content.setSpacing(true);
        content.setWidth("720px");
        content.setDefaultHorizontalComponentAlignment(FlexComponent.Alignment.STRETCH);

        // Row: Digital processing + App user
        HorizontalLayout digitalRow = new HorizontalLayout();
        digitalRow.setWidthFull();
        digitalRow.setAlignItems(FlexComponent.Alignment.BASELINE);
        digitalRow.setJustifyContentMode(FlexComponent.JustifyContentMode.START);
        digitalProcessing.getStyle().set("margin-right", "12px");
        digitalRow.add(digitalProcessing);

        // App user selector full width
        appUser.setWidthFull();
        content.add(digitalRow, appUser);

        // Appointment (Pickup)
        H3 pickupApptTitle = new H3("Termin (Abholung)");
        pickupApptTitle.getStyle().set("margin", "0");
        pickupTime = new TimePicker("Uhrzeit");
        pickupTime.setLocale(java.util.Locale.GERMANY);
        HorizontalLayout pickupApptRow = new HorizontalLayout(pickupDate, pickupTime);
        pickupApptRow.setWidthFull();
        pickupApptRow.setSpacing(true);
        pickupDate.setWidth("50%");
        pickupTime.setWidth("50%");
        content.add(pickupApptTitle, pickupApptRow);

        // Appointment (Delivery)
        H3 deliveryApptTitle = new H3("Termin (Lieferung)");
        deliveryApptTitle.getStyle().set("margin", "0");
        deliveryTime = new TimePicker("Uhrzeit");
        deliveryTime.setLocale(java.util.Locale.GERMANY);
        HorizontalLayout deliveryApptRow = new HorizontalLayout(deliveryDate, deliveryTime);
        deliveryApptRow.setWidthFull();
        deliveryApptRow.setSpacing(true);
        deliveryDate.setWidth("50%");
        deliveryTime.setWidth("50%");
        content.add(deliveryApptTitle, deliveryApptRow);

        tabContent.add(content);
        return tabContent;
    }

    private Component createCargoTab() {
        VerticalLayout tabContent = new VerticalLayout();
        tabContent.setSizeFull();
        tabContent.setPadding(true);
        tabContent.setSpacing(true);

        // Add cargo section
        tabContent.add(createCargoSection());

        return tabContent;
    }

    private Component createTasksTab() {
        VerticalLayout tabContent = new VerticalLayout();
        tabContent.setSizeFull();
        tabContent.setPadding(true);
        tabContent.setSpacing(true);

        // Add tasks and notes section
        tabContent.add(createTasksAndNotesSection());

        return tabContent;
    }

    private Component createPriceAndSubmitTab() {
        VerticalLayout tabContent = new VerticalLayout();
        tabContent.setSizeFull();
        tabContent.setPadding(true);
        tabContent.setSpacing(true);
        tabContent.setDefaultHorizontalComponentAlignment(FlexComponent.Alignment.STRETCH);

        // Container with full width like other tabs
        VerticalLayout content = new VerticalLayout();
        content.setPadding(false);
        content.setSpacing(true);
        content.setWidthFull();
        content.setDefaultHorizontalComponentAlignment(FlexComponent.Alignment.STRETCH);

        // Route Info Box (ganz oben)
        routeInfoBox = new VerticalLayout();
        routeInfoBox.setPadding(true);
        routeInfoBox.setSpacing(true);
        routeInfoBox.getStyle().set("border", "1px solid var(--lumo-primary-color-50pct)");
        routeInfoBox.getStyle().set("border-radius", "var(--lumo-border-radius-m)");
        routeInfoBox.getStyle().set("background-color", "var(--lumo-primary-color-10pct)");
        routeInfoBox.setWidthFull();
        routeInfoBox.setDefaultHorizontalComponentAlignment(FlexComponent.Alignment.STRETCH);
        routeInfoBox.setVisible(false); // Initial versteckt

        H3 routeTitle = new H3("Streckeninformation");
        routeTitle.getStyle().set("margin", "0");
        routeTitle.getStyle().set("color", "var(--lumo-primary-text-color)");

        HorizontalLayout routeRow = new HorizontalLayout();
        routeRow.setWidthFull();
        routeRow.setJustifyContentMode(FlexComponent.JustifyContentMode.BETWEEN);
        routeRow.setAlignItems(FlexComponent.Alignment.CENTER);

        Span distanceLabel = new Span("Entfernung:");
        routeDistanceLabel = new Span("-");
        routeDistanceLabel.getStyle().set("font-weight", "bold");
        routeDistanceLabel.getStyle().set("font-size", "var(--lumo-font-size-l)");
        routeDistanceLabel.getStyle().set("color", "var(--lumo-primary-text-color)");

        routeRow.add(distanceLabel, routeDistanceLabel);

        HorizontalLayout durationRow = new HorizontalLayout();
        durationRow.setWidthFull();
        durationRow.setJustifyContentMode(FlexComponent.JustifyContentMode.BETWEEN);
        durationRow.setAlignItems(FlexComponent.Alignment.CENTER);

        Span durationLabel = new Span("Fahrtzeit:");
        routeDurationLabel = new Span("-");
        routeDurationLabel.getStyle().set("font-weight", "bold");
        routeDurationLabel.getStyle().set("color", "var(--lumo-secondary-text-color)");

        durationRow.add(durationLabel, routeDurationLabel);

        routeInfoBox.add(routeTitle, routeRow, durationRow);
        content.add(routeInfoBox);

        // Manuelle Streckeneingabe (wenn keine Route berechnet wurde)
        manualRouteInputBox = new VerticalLayout();
        manualRouteInputBox.setPadding(true);
        manualRouteInputBox.setSpacing(true);
        manualRouteInputBox.getStyle().set("border", "1px solid var(--lumo-contrast-30pct)");
        manualRouteInputBox.getStyle().set("border-radius", "var(--lumo-border-radius-m)");
        manualRouteInputBox.getStyle().set("background-color", "var(--lumo-contrast-5pct)");
        manualRouteInputBox.setWidthFull();
        manualRouteInputBox.setDefaultHorizontalComponentAlignment(FlexComponent.Alignment.STRETCH);
        manualRouteInputBox.setVisible(true); // Initial sichtbar

        H3 manualRouteTitle = new H3("Streckeninformation (manuelle Eingabe)");
        manualRouteTitle.getStyle().set("margin", "0");
        manualRouteTitle.getStyle().set("color", "var(--lumo-secondary-text-color)");

        HorizontalLayout manualInputRow = new HorizontalLayout();
        manualInputRow.setWidthFull();
        manualInputRow.setSpacing(true);

        manualDistanceInput = new com.vaadin.flow.component.textfield.NumberField("Entfernung (km)");
        manualDistanceInput.setWidthFull();
        manualDistanceInput.setPlaceholder("z.B. 125,5");
        manualDistanceInput.setMin(0);
        manualDistanceInput.setStep(0.1);
        manualDistanceInput.setClearButtonVisible(true);
        manualDistanceInput.addValueChangeListener(e -> {
            // Preise aktualisieren wenn sich die Distanz ändert
            updatePriceSummary();
            if (servicesGrid != null) {
                servicesGrid.getDataProvider().refreshAll();
            }
        });

        manualDurationInput = new com.vaadin.flow.component.textfield.IntegerField("Fahrtzeit (Minuten)");
        manualDurationInput.setWidthFull();
        manualDurationInput.setPlaceholder("z.B. 90");
        manualDurationInput.setMin(0);
        manualDurationInput.setStep(1);
        manualDurationInput.setClearButtonVisible(true);

        manualInputRow.add(manualDistanceInput, manualDurationInput);

        Span manualRouteHint = new Span("Bitte geben Sie die Entfernung und Fahrtzeit ein, da keine automatische Routenberechnung durchgeführt wurde.");
        manualRouteHint.getStyle().set("font-size", "var(--lumo-font-size-s)");
        manualRouteHint.getStyle().set("color", "var(--lumo-secondary-text-color)");
        manualRouteHint.getStyle().set("font-style", "italic");

        manualRouteInputBox.add(manualRouteTitle, manualInputRow, manualRouteHint);
        content.add(manualRouteInputBox);

        // Title
        H3 servicesTitle = new H3("Leistungen");
        servicesTitle.getStyle().set("margin", "0");
        content.add(servicesTitle);

        // Services Grid
        servicesGrid = new Grid<>();
        servicesGrid.setWidthFull();
        servicesGrid.setHeight("250px");
        servicesGrid.setItems(selectedServices);

        servicesGrid.addColumn(Service::getName).setHeader("Leistung").setSortable(true);
        servicesGrid.addColumn(service -> {
            if (service.getCalculationBasis() != null) {
                return switch (service.getCalculationBasis()) {
                case DISTANCE -> "Gefahrene Kilometer";
                case TIME -> "Zeit";
                case FLAT_RATE -> "Pauschal";
                };
            }
            return "";
        }).setHeader("Berechnung").setSortable(true);
        servicesGrid.addColumn(service -> {
            // Get route distance for distance-based calculations (berechnet oder manuell)
            Double routeDistance = getEffectiveRouteDistance();
            BigDecimal price = calculateServicePrice(service, routeDistance);
            if (price.compareTo(BigDecimal.ZERO) > 0) {
                return price.setScale(2, RoundingMode.HALF_UP) + " €";
            }
            // Show price info if no route calculated yet
            if (service.getCalculationBasis() == Service.CalculationBasis.DISTANCE && routeDistance == null) {
                return service.getPricePerKilometer().setScale(2, RoundingMode.HALF_UP) + " €/km (Route fehlt)";
            }
            return service.getEffectivePrice() != null
                    ? service.getEffectivePrice().setScale(2, RoundingMode.HALF_UP) + " €"
                    : "";
        }).setHeader("Preis").setSortable(false);
        servicesGrid.addColumn(service -> {
            if (service.getVatRate() != null) {
                return service.getVatRate().multiply(new BigDecimal("100")).setScale(0, RoundingMode.HALF_UP) + " %";
            }
            return "";
        }).setHeader("USt").setSortable(true);
        servicesGrid.addComponentColumn(service -> {
            // Verbindliche Leistungen können nicht gelöscht werden
            if (service.isMandatory()) {
                return new Span(""); // Leeres Element statt Löschen-Button
            }
            Button removeButton = new Button(new Icon(VaadinIcon.TRASH));
            removeButton.addThemeVariants(ButtonVariant.LUMO_ERROR, ButtonVariant.LUMO_TERTIARY,
                    ButtonVariant.LUMO_SMALL);
            removeButton.addClickListener(e -> {
                selectedServices.remove(service);
                servicesGrid.getDataProvider().refreshAll();
                updatePriceSummary();
                triggerValidation();
                updateTabLabels();
            });
            return removeButton;
        }).setHeader("Aktion").setAutoWidth(true).setFlexGrow(0);

        content.add(servicesGrid);

        // Add Service Button
        Button addServiceButton = new Button("Leistung hinzufügen", new Icon(VaadinIcon.PLUS));
        addServiceButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        addServiceButton.addClickListener(e -> openAddServiceDialog());
        content.add(addServiceButton);

        // Price Summary
        VerticalLayout summaryLayout = new VerticalLayout();
        summaryLayout.setPadding(true);
        summaryLayout.setSpacing(true);
        summaryLayout.getStyle().set("border", "1px solid var(--lumo-contrast-20pct)");
        summaryLayout.getStyle().set("border-radius", "var(--lumo-border-radius-m)");
        summaryLayout.getStyle().set("background-color", "var(--lumo-contrast-5pct)");
        summaryLayout.setWidthFull();
        summaryLayout.setDefaultHorizontalComponentAlignment(FlexComponent.Alignment.STRETCH);

        H3 summaryTitle = new H3("Zusammenfassung");
        summaryTitle.getStyle().set("margin", "0");
        summaryLayout.add(summaryTitle);

        // Net total
        HorizontalLayout netRow = new HorizontalLayout();
        netRow.setWidthFull();
        netRow.setJustifyContentMode(FlexComponent.JustifyContentMode.BETWEEN);
        Span netLabel = new Span("Nettosumme:");
        netTotalLabel = new Span("0,00 €");
        netTotalLabel.getStyle().set("font-weight", "bold");
        netRow.add(netLabel, netTotalLabel);
        summaryLayout.add(netRow);

        // VAT total
        HorizontalLayout vatRow = new HorizontalLayout();
        vatRow.setWidthFull();
        vatRow.setJustifyContentMode(FlexComponent.JustifyContentMode.BETWEEN);
        Span vatLabel = new Span("Umsatzsteuer:");
        vatTotalLabel = new Span("0,00 €");
        vatTotalLabel.getStyle().set("font-weight", "bold");
        vatRow.add(vatLabel, vatTotalLabel);
        summaryLayout.add(vatRow);

        // Gross total
        HorizontalLayout grossRow = new HorizontalLayout();
        grossRow.setWidthFull();
        grossRow.setJustifyContentMode(FlexComponent.JustifyContentMode.BETWEEN);
        Span grossLabel = new Span("Bruttosumme:");
        grossLabel.getStyle().set("font-size", "var(--lumo-font-size-l)");
        grossTotalLabel = new Span("0,00 €");
        grossTotalLabel.getStyle().set("font-size", "var(--lumo-font-size-l)");
        grossTotalLabel.getStyle().set("font-weight", "bold");
        grossTotalLabel.getStyle().set("color", "var(--lumo-primary-text-color)");
        grossRow.add(grossLabel, grossTotalLabel);
        summaryLayout.add(grossRow);

        content.add(summaryLayout);

        tabContent.add(content);
        return tabContent;
    }

    private void openAddServiceDialog() {
        Dialog dialog = new Dialog();
        dialog.setHeaderTitle("Leistung auswählen");
        dialog.setWidth("500px");

        VerticalLayout dialogContent = new VerticalLayout();
        dialogContent.setPadding(true);
        dialogContent.setSpacing(true);

        // Load available services for current user
        List<Service> availableServices = serviceRepository
                .findByUserId(securityService.getCurrentDatabaseUser().getId().toString());

        ComboBox<Service> serviceCombo = new ComboBox<>("Leistung");
        serviceCombo.setWidthFull();
        serviceCombo.setItems(availableServices);
        serviceCombo.setItemLabelGenerator(service -> {
            // Only show price for FLAT_RATE services
            if (service.getCalculationBasis() == Service.CalculationBasis.FLAT_RATE
                    && service.getEffectivePrice() != null) {
                return service.getName() + " (" + service.getEffectivePrice().setScale(2, RoundingMode.HALF_UP) + " €)";
            }
            return service.getName();
        });
        serviceCombo.setPlaceholder("Leistung auswählen...");
        serviceCombo.setRequired(true);

        dialogContent.add(serviceCombo);

        HorizontalLayout buttonLayout = new HorizontalLayout();
        buttonLayout.setWidthFull();
        buttonLayout.setJustifyContentMode(FlexComponent.JustifyContentMode.END);
        buttonLayout.setSpacing(true);

        Button cancelButton = new Button("Abbrechen", e -> dialog.close());
        cancelButton.addThemeVariants(ButtonVariant.LUMO_TERTIARY);

        Button addButton = new Button("Hinzufügen", e -> {
            if (serviceCombo.getValue() != null) {
                selectedServices.add(serviceCombo.getValue());
                servicesGrid.getDataProvider().refreshAll();
                updatePriceSummary();
                triggerValidation();
                updateTabLabels();
                dialog.close();
            }
        });
        addButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);

        buttonLayout.add(cancelButton, addButton);
        dialogContent.add(buttonLayout);

        dialog.add(dialogContent);
        dialog.open();
    }

    private void updatePriceSummary() {
        BigDecimal netTotal = BigDecimal.ZERO;
        BigDecimal vatTotal = BigDecimal.ZERO;
        BigDecimal grossTotal = BigDecimal.ZERO;

        // Get route distance for distance-based calculations (berechnet oder manuell)
        Double routeDistance = getEffectiveRouteDistance();

        for (Service service : selectedServices) {
            BigDecimal price = calculateServicePrice(service, routeDistance);
            BigDecimal vatRate = service.getVatRate() != null ? service.getVatRate() : BigDecimal.ZERO;

            netTotal = netTotal.add(price);
            BigDecimal vatAmount = price.multiply(vatRate);
            vatTotal = vatTotal.add(vatAmount);
            grossTotal = grossTotal.add(price.add(vatAmount));
        }

        netTotalLabel.setText(netTotal.setScale(2, RoundingMode.HALF_UP).toString().replace(".", ",") + " €");
        vatTotalLabel.setText(vatTotal.setScale(2, RoundingMode.HALF_UP).toString().replace(".", ",") + " €");
        grossTotalLabel.setText(grossTotal.setScale(2, RoundingMode.HALF_UP).toString().replace(".", ",") + " €");
    }

    /**
     * Calculates the actual price for a service based on its calculation basis and
     * route distance (for distance-based services).
     */
    private BigDecimal calculateServicePrice(Service service, Double routeDistance) {
        return calculateServicePrice(service, routeDistance, null);
    }

    private BigDecimal calculateServicePrice(Service service, Double routeDistance, Integer durationSeconds) {
        if (service.getCalculationBasis() == null) {
            return BigDecimal.ZERO;
        }

        switch (service.getCalculationBasis()) {
        case FLAT_RATE:
            return service.getPrice() != null ? service.getPrice() : BigDecimal.ZERO;

        case DISTANCE:
            if (service.getPricePerKilometer() != null && routeDistance != null && routeDistance > 0) {
                return service.getPricePerKilometer().multiply(BigDecimal.valueOf(routeDistance));
            }
            return BigDecimal.ZERO;

        case TIME:
            if (service.getPricePer15Minutes() != null && durationSeconds != null && durationSeconds > 0) {
                // Dauer in 15-Minuten-Einheiten umrechnen (aufrunden)
                int units = durationSeconds / 900; // 900 Sekunden = 15 Minuten
                if (durationSeconds % 900 > 0) units++; // Aufrunden
                return service.getPricePer15Minutes().multiply(BigDecimal.valueOf(units));
            }
            return BigDecimal.ZERO;

        default:
            return BigDecimal.ZERO;
        }
    }

    private VerticalLayout createPickupSection() {
        VerticalLayout section = new VerticalLayout();
        section.setSpacing(true);
        section.setPadding(true);
        section.setWidthFull();

        // Hellgrauer Rahmen hinzufügen
        section.getStyle().set("border", "1px solid var(--lumo-contrast-20pct)");
        section.getStyle().set("border-radius", "var(--lumo-border-radius-m)");
        section.getStyle().set("background-color", "var(--lumo-base-color)");

        H3 title = new H3("Abholadresse");
        title.getStyle().set("margin", "0");

        HorizontalLayout titleLayout = new HorizontalLayout();
        titleLayout.setWidthFull();
        titleLayout.setJustifyContentMode(FlexComponent.JustifyContentMode.START);
        titleLayout.setDefaultVerticalComponentAlignment(FlexComponent.Alignment.CENTER);
        titleLayout.add(title);

        // Alle einzelnen Controls auf volle Breite setzen
        pickupCompany.setWidthFull();
        pickupSalutation.setWidthFull();
        pickupFirstName.setWidthFull();
        pickupLastName.setWidthFull();
        pickupPhone.setWidthFull();
        pickupAddressAddition.setWidthFull();
        savePickupAddress.setWidthFull();

        section.add(titleLayout);
        section.add(pickupCompany);
        section.add(pickupSalutation);
        section.add(pickupFirstName);
        section.add(pickupLastName);
        section.add(pickupPhone);

        HorizontalLayout streetLayout = new HorizontalLayout();
        streetLayout.setWidthFull();
        streetLayout.setSpacing(true);
        streetLayout.add(pickupStreet, pickupHouseNumber);
        pickupStreet.setWidth("70%");
        pickupHouseNumber.setWidth("30%");
        section.add(streetLayout);

        section.add(pickupAddressAddition);

        // zip/city row
        HorizontalLayout zipCityLayout = new HorizontalLayout();
        zipCityLayout.setWidthFull();
        zipCityLayout.setSpacing(true);
        zipCityLayout.add(pickupZip, pickupCity);
        pickupZip.setWidth("30%");
        pickupCity.setWidth("70%");
        section.add(zipCityLayout);

        section.add(savePickupAddress);

        return section;
    }

    private VerticalLayout createDeliverySection() {
        VerticalLayout section = new VerticalLayout();
        section.setSpacing(true);
        section.setPadding(true);
        section.setWidthFull();

        // Hellgrauer Rahmen hinzufügen
        section.getStyle().set("border", "1px solid var(--lumo-contrast-20pct)");
        section.getStyle().set("border-radius", "var(--lumo-border-radius-m)");
        section.getStyle().set("background-color", "var(--lumo-base-color)");

        H3 title = new H3("Lieferadresse");
        title.getStyle().set("margin", "0");

        HorizontalLayout titleLayout = new HorizontalLayout();
        titleLayout.setWidthFull();
        titleLayout.setJustifyContentMode(FlexComponent.JustifyContentMode.START);
        titleLayout.setDefaultVerticalComponentAlignment(FlexComponent.Alignment.CENTER);
        titleLayout.add(title);

        // Alle einzelnen Controls auf volle Breite setzen
        deliveryCompany.setWidthFull();
        deliverySalutation.setWidthFull();
        deliveryFirstName.setWidthFull();
        deliveryLastName.setWidthFull();
        deliveryPhone.setWidthFull();
        deliveryAddressAddition.setWidthFull();
        saveDeliveryAddress.setWidthFull();

        section.add(titleLayout);
        section.add(deliveryCompany);
        section.add(deliverySalutation);
        section.add(deliveryFirstName);
        section.add(deliveryLastName);
        section.add(deliveryPhone);

        HorizontalLayout streetLayout = new HorizontalLayout();
        streetLayout.setWidthFull();
        streetLayout.setSpacing(true);
        streetLayout.add(deliveryStreet, deliveryHouseNumber);
        deliveryStreet.setWidth("70%");
        deliveryHouseNumber.setWidth("30%");
        section.add(streetLayout);

        section.add(deliveryAddressAddition);

        HorizontalLayout zipCityLayout = new HorizontalLayout();
        zipCityLayout.setWidthFull();
        zipCityLayout.setSpacing(true);
        zipCityLayout.add(deliveryZip, deliveryCity);
        deliveryZip.setWidth("30%");
        deliveryCity.setWidth("70%");
        section.add(zipCityLayout);

        section.add(saveDeliveryAddress);

        return section;
    }

    private void setupCompanyAutocomplete(ComboBox<String> companyField, boolean isPickup) {
        // Get all customers for the current owner
        List<Customer> allCustomers = customerService.findAllForCurrentOwner();

        // Extract unique company names (filter out null/empty values)
        List<String> companyNames = allCustomers.stream().map(Customer::getCompanyName)
                .filter(name -> name != null && !name.trim().isEmpty()).distinct().sorted().toList();

        // Set items for autocomplete
        companyField.setItems(companyNames);

        // Add selection listener to auto-fill address fields when company is selected
        companyField.addValueChangeListener(event -> {
            String selectedCompany = event.getValue();
            if (selectedCompany == null || selectedCompany.trim().isEmpty()) {
                return;
            }

            // Streckeninformationen zurücksetzen, da sich die Adresse ändert
            resetRouteInformation();

            // Find the first customer with this company name
            Optional<Customer> matchingCustomer = allCustomers.stream()
                    .filter(c -> selectedCompany.equals(c.getCompanyName())).findFirst();

            if (matchingCustomer.isPresent()) {
                Customer customer = matchingCustomer.get();

                if (isPickup) {
                    // Fill pickup address fields
                    if (customer.getTitle() != null && ("Herr".equalsIgnoreCase(customer.getTitle())
                            || "Frau".equalsIgnoreCase(customer.getTitle())
                            || "Divers".equalsIgnoreCase(customer.getTitle()))) {
                        pickupSalutation.setValue(customer.getTitle());
                    }
                    if (customer.getFirstname() != null)
                        pickupFirstName.setValue(customer.getFirstname());
                    if (customer.getLastName() != null)
                        pickupLastName.setValue(customer.getLastName());
                    if (customer.getTelephone() != null)
                        pickupPhone.setValue(customer.getTelephone());
                    if (customer.getStreet() != null)
                        pickupStreet.setValue(customer.getStreet());
                    if (customer.getHouseNumber() != null)
                        pickupHouseNumber.setValue(customer.getHouseNumber());
                    if (customer.getAddressAddition() != null)
                        pickupAddressAddition.setValue(customer.getAddressAddition());
                    if (customer.getZip() != null)
                        pickupZip.setValue(customer.getZip());
                    if (customer.getCity() != null)
                        pickupCity.setValue(customer.getCity());

                    // Deactivate save checkbox since customer already exists
                    savePickupAddress.setValue(false);
                } else {
                    // Fill delivery address fields
                    if (customer.getTitle() != null && ("Herr".equalsIgnoreCase(customer.getTitle())
                            || "Frau".equalsIgnoreCase(customer.getTitle())
                            || "Divers".equalsIgnoreCase(customer.getTitle()))) {
                        deliverySalutation.setValue(customer.getTitle());
                    }
                    if (customer.getFirstname() != null)
                        deliveryFirstName.setValue(customer.getFirstname());
                    if (customer.getLastName() != null)
                        deliveryLastName.setValue(customer.getLastName());
                    if (customer.getTelephone() != null)
                        deliveryPhone.setValue(customer.getTelephone());
                    if (customer.getStreet() != null)
                        deliveryStreet.setValue(customer.getStreet());
                    if (customer.getHouseNumber() != null)
                        deliveryHouseNumber.setValue(customer.getHouseNumber());
                    if (customer.getAddressAddition() != null)
                        deliveryAddressAddition.setValue(customer.getAddressAddition());
                    if (customer.getZip() != null)
                        deliveryZip.setValue(customer.getZip());
                    if (customer.getCity() != null)
                        deliveryCity.setValue(customer.getCity());

                    // Deactivate save checkbox since customer already exists
                    saveDeliveryAddress.setValue(false);
                }
            }
        });

        // Handle custom values (when user types something not in the list)
        companyField.addCustomValueSetListener(event -> {
            String customValue = event.getDetail();
            companyField.setValue(customValue);

            // Streckeninformationen zurücksetzen
            resetRouteInformation();

            // Reactivate save checkbox for custom values
            if (isPickup) {
                savePickupAddress.setValue(true);
            } else {
                saveDeliveryAddress.setValue(true);
            }
        });
    }

    private void setupValidation() {
        // Bind pickup address fields with validation
        binder.forField(pickupFirstName).asRequired("").bind(Job::getPickupFirstName, Job::setPickupFirstName);

        binder.forField(pickupLastName).asRequired("").bind(Job::getPickupLastName, Job::setPickupLastName);

        binder.forField(pickupStreet).asRequired("").bind(Job::getPickupStreet, Job::setPickupStreet);

        binder.forField(pickupHouseNumber).asRequired("").bind(Job::getPickupHouseNumber, Job::setPickupHouseNumber);

        binder.forField(pickupZip).asRequired("").bind(Job::getPickupZip, Job::setPickupZip);

        binder.forField(pickupCity).asRequired("").bind(Job::getPickupCity, Job::setPickupCity);

        // Bind delivery address fields with validation
        binder.forField(deliveryFirstName).asRequired("").bind(Job::getDeliveryFirstName, Job::setDeliveryFirstName);

        binder.forField(deliveryLastName).asRequired("").bind(Job::getDeliveryLastName, Job::setDeliveryLastName);

        binder.forField(deliveryStreet).asRequired("").bind(Job::getDeliveryStreet, Job::setDeliveryStreet);

        binder.forField(deliveryHouseNumber).asRequired("").bind(Job::getDeliveryHouseNumber,
                Job::setDeliveryHouseNumber);

        binder.forField(deliveryZip).asRequired("").bind(Job::getDeliveryZip, Job::setDeliveryZip);

        binder.forField(deliveryCity).asRequired("").bind(Job::getDeliveryCity, Job::setDeliveryCity);

        // Price wird manuell in submit() berechnet und gesetzt - kein Binder notwendig

        // Bind date picker fields with validation
        binder.forField(pickupDate).asRequired("")
                .withValidator(date -> date == null || !date.isBefore(LocalDate.now()),
                        "Das Abholdatum darf nicht in der Vergangenheit liegen")
                .bind(Job::getPickupDate, Job::setPickupDate);

        binder.forField(deliveryDate).asRequired("")
                .withValidator(date -> date == null || !date.isBefore(LocalDate.now()),
                        "Das Lieferdatum darf nicht in der Vergangenheit liegen")
                .bind(Job::getDeliveryDate, Job::setDeliveryDate);

        // Bind time picker fields (optional)
        binder.bind(pickupTime, Job::getPickupTime, Job::setPickupTime);
        binder.bind(deliveryTime, Job::getDeliveryTime, Job::setDeliveryTime);

        // Bind customerSelection field with validation
        binder.forField(customerSelection).asRequired("").bind(Job::getCustomerSelection, Job::setCustomerSelection);

        // Bind optional fields without validation
        binder.bind(pickupCompany, Job::getPickupCompany, Job::setPickupCompany);
        binder.bind(pickupSalutation, Job::getPickupSalutation, Job::setPickupSalutation);
        binder.bind(pickupPhone, Job::getPickupPhone, Job::setPickupPhone);
        binder.bind(pickupAddressAddition, Job::getPickupAddressAddition, Job::setPickupAddressAddition);

        binder.bind(deliveryCompany, Job::getDeliveryCompany, Job::setDeliveryCompany);
        binder.bind(deliverySalutation, Job::getDeliverySalutation, Job::setDeliverySalutation);
        binder.bind(deliveryPhone, Job::getDeliveryPhone, Job::setDeliveryPhone);
        binder.bind(deliveryAddressAddition, Job::getDeliveryAddressAddition, Job::setDeliveryAddressAddition);

        binder.forField(digitalProcessing).bind(Job::isDigitalProcessing,
                (job, value) -> job.setDigitalProcessing(Boolean.TRUE.equals(value)));

        // Bind appUser with converter: AppUser object <-> String ID
        binder.forField(appUser).withConverter(
                // Convert AppUser to String (ID)
                user -> user != null ? user.getId().toHexString() : null,
                // Convert String (ID) back to AppUser
                id -> {
                    if (id == null || id.trim().isEmpty())
                        return null;
                    return availableAppUsers.stream().filter(user -> user.getId().toHexString().equals(id)).findFirst()
                            .orElse(null);
                })
                // Require App-Nutzer when digital processing is enabled
                .withValidator(selectedUserId -> {
                    boolean digital = Boolean.TRUE.equals(digitalProcessing.getValue());
                    boolean hasUser = selectedUserId != null && !selectedUserId.trim().isEmpty();
                    return !digital || hasUser;
                }, "Bitte App-Nutzer auswählen, wenn Digitale Abwicklung aktiv ist")
                .bind(Job::getAppUser, Job::setAppUser);

        // Toggle required indicator and visibility for App-Nutzer based on
        // digitalProcessing
        digitalProcessing.addValueChangeListener(e -> {
            boolean required = Boolean.TRUE.equals(e.getValue());
            appUser.setRequiredIndicatorVisible(required);
            appUser.setVisible(required);

            // Enable/disable tasks tab based on digital processing
            if (tasksTab != null) {
                tasksTab.setEnabled(required);
            }
            if (!required) {
                // Clear app user and all tasks when digital processing is disabled
                appUser.clear();
                tasksState.clear();
                if (tasksList != null) {
                    tasksList.removeAll();
                }
            } else {
                // Add an empty task row when digital processing is re-enabled
                if (tasksState.isEmpty() && tasksList != null) {
                    createTaskRow();
                }
            }

            triggerValidation();
            updateTabLabels();
        });
        // Also revalidate when appUser changes
        appUser.addValueChangeListener(e -> {
            triggerValidation();
            updateTabLabels();
        });
        // Initialize required indicator and visibility state
        boolean digitalInitial = Boolean.TRUE.equals(digitalProcessing.getValue());
        appUser.setRequiredIndicatorVisible(digitalInitial);
        appUser.setVisible(digitalInitial);

        // Set up validation triggers and visual styling
        setupValidationTriggers();

        // Trigger initial validation when view is displayed
        triggerValidation();

        // Update tab labels with initial validation state
        updateTabLabels();
    }

    private void setupValidationTriggers() {
        // List of all required fields
        TextField[] requiredTextFields = { pickupFirstName, pickupLastName, pickupStreet, pickupHouseNumber, pickupZip,
                pickupCity, deliveryFirstName, deliveryLastName, deliveryStreet, deliveryHouseNumber, deliveryZip,
                deliveryCity };

        // List of required date fields
        DatePicker[] requiredDateFields = { pickupDate, deliveryDate };

        // Add validation listener for customerSelection ComboBox
        customerSelection.addValueChangeListener(event -> {
            triggerValidation();
            updateTabLabels();
        });

        // Add value change listeners to trigger validation on every change for text
        // fields
        for (TextField field : requiredTextFields) {
            field.addValueChangeListener(event -> {
                triggerValidation();
                updateFieldStyling(field);
                updateTabLabels();
            });

            // Add focus listeners for immediate visual feedback
            field.addFocusListener(event -> updateFieldStyling(field));
            field.addBlurListener(event -> updateFieldStyling(field));

            // Set initial styling
            updateFieldStyling(field);
        }

        // Add value change listeners for date fields
        for (DatePicker field : requiredDateFields) {
            field.addValueChangeListener(event -> {
                triggerValidation();
                updateDateFieldStyling(field);
                updateTabLabels();
            });

            // Add focus listeners for immediate visual feedback
            field.addFocusListener(event -> updateDateFieldStyling(field));
            field.addBlurListener(event -> updateDateFieldStyling(field));

            // Set initial styling
            updateDateFieldStyling(field);
        }
    }

    private void triggerValidation() {
        // Create a temporary job object to trigger validation
        binder.validate();

        // Update submit button state based on all validation checks
        if (submitButton != null) {
            boolean hasErrors = hasAddressValidationErrors() || hasAppointmentValidationErrors()
                    || hasCargoValidationErrors() || hasPriceValidationErrors() || hasTasksValidationErrors();
            submitButton.setEnabled(!hasErrors);
        }
    }

    private void updateFieldStyling(TextField field) {
        String value = field.getValue();
        boolean isEmpty = value == null || value.trim().isEmpty();

        if (isEmpty) {
            // Apply transparent red background only to the input field, not the label
            field.getStyle().set("--vaadin-input-field-background", "rgba(255, 0, 0, 0.1)");
            field.getStyle().set("--vaadin-input-field-border-color", "rgba(255, 0, 0, 0.3)");
        } else {
            // Remove styling when field is filled
            field.getStyle().remove("--vaadin-input-field-background");
            field.getStyle().remove("--vaadin-input-field-border-color");
        }
    }

    private void updateDateFieldStyling(DatePicker field) {
        boolean isEmpty = field.getValue() == null;

        if (isEmpty) {
            // Apply transparent red background only to the input field, not the label
            field.getStyle().set("--vaadin-input-field-background", "rgba(255, 0, 0, 0.1)");
            field.getStyle().set("--vaadin-input-field-border-color", "rgba(255, 0, 0, 0.3)");
        } else {
            // Remove styling when field is filled
            field.getStyle().remove("--vaadin-input-field-background");
            field.getStyle().remove("--vaadin-input-field-border-color");
        }
    }

    private void updateTabLabels() {
        // Check validation state for each tab and update labels with exclamation marks
        updateTabLabel(addressesTab, "Auftraggeber & Adressen", hasAddressValidationErrors());
        updateTabLabel(appointmentsTab, "Termine & Verarbeitung", hasAppointmentValidationErrors());
        updateTabLabel(cargoTab, "Ladung", hasCargoValidationErrors());
        updateTabLabel(tasksTab, "Aufgaben", hasTasksValidationErrors());
        updateTabLabel(priceTab, "Preis & Abschluss", hasPriceValidationErrors());
    }

    private void updateTabLabel(com.vaadin.flow.component.tabs.Tab tab, String baseLabel, boolean hasErrors) {
        if (tab == null) {
            return;
        }
        if (hasErrors) {
            tab.setLabel(baseLabel + " ⚠️");
        } else {
            tab.setLabel(baseLabel);
        }
    }

    private boolean hasAddressValidationErrors() {
        // Check customer selection
        boolean customerSelectionEmpty = customerSelection.getValue() == null
                || customerSelection.getValue().trim().isEmpty();

        // Check pickup address fields
        boolean pickupErrors = isFieldEmpty(pickupFirstName) || isFieldEmpty(pickupLastName)
                || isFieldEmpty(pickupStreet) || isFieldEmpty(pickupHouseNumber) || isFieldEmpty(pickupZip)
                || isFieldEmpty(pickupCity);

        // Check delivery address fields
        boolean deliveryErrors = isFieldEmpty(deliveryFirstName) || isFieldEmpty(deliveryLastName)
                || isFieldEmpty(deliveryStreet) || isFieldEmpty(deliveryHouseNumber) || isFieldEmpty(deliveryZip)
                || isFieldEmpty(deliveryCity);

        return customerSelectionEmpty || pickupErrors || deliveryErrors;
    }

    private boolean hasAppointmentValidationErrors() {
        LocalDate today = LocalDate.now();
        return pickupDate.getValue() == null || deliveryDate.getValue() == null || pickupDate.getValue().isBefore(today)
                || deliveryDate.getValue().isBefore(today);
    }

    private boolean hasCargoValidationErrors() {
        // Check if ALL cargo items have all required fields filled
        // When multiple cargo rows exist, ALL must be complete
        if (cargoItemsState.isEmpty()) {
            return true; // No cargo items at all - show warning
        }

        // Check that ALL cargo items are complete
        // A cargo item is considered complete if it has: Description, Quantity, Weight,
        // Length, Width, Height
        boolean allCargoItemsValid = cargoItemsState.stream()
                .allMatch(cargoItem -> cargoItem != null && cargoItem.getDescription() != null
                        && !cargoItem.getDescription().trim().isEmpty() && cargoItem.getQuantity() != null
                        && cargoItem.getQuantity() > 0 && cargoItem.getWeightKg() != null && cargoItem.getWeightKg() > 0
                        && cargoItem.getLengthMm() != null && cargoItem.getLengthMm() > 0
                        && cargoItem.getWidthMm() != null && cargoItem.getWidthMm() > 0
                        && cargoItem.getHeightMm() != null && cargoItem.getHeightMm() > 0);

        return !allCargoItemsValid; // Return true if ANY cargo item is incomplete (show warning)
    }

    private boolean hasTasksValidationErrors() {
        for (BaseTask task : tasksState) {
            // Check if any ConfirmationTask has an empty description or buttonText
            // (required fields)
            if (task instanceof ConfirmationTask confirmationTask) {
                String description = task.getDescription();
                if (description == null || description.trim().isEmpty()) {
                    return true;
                }
                String buttonText = confirmationTask.getButtonText();
                if (buttonText == null || buttonText.trim().isEmpty()) {
                    return true;
                }
            }
            // Check if any TodoListTask has at least one non-empty todo item
            if (task instanceof TodoListTask todoListTask) {
                List<String> todoItems = todoListTask.getTodoItems();
                if (todoItems == null || todoItems.isEmpty()) {
                    return true;
                }
                // Check if at least one todo item is non-empty
                boolean hasValidTodoItem = todoItems.stream().anyMatch(item -> item != null && !item.trim().isEmpty());
                if (!hasValidTodoItem) {
                    return true;
                }
            }
        }
        return false;
    }

    private boolean hasPriceValidationErrors() {
        // Price tab is valid when at least one service is selected
        return selectedServices == null || selectedServices.isEmpty();
    }

    private boolean isFieldEmpty(TextField field) {
        String value = field.getValue();
        return value == null || value.trim().isEmpty();
    }

    private void submit() {
        try {
            Job job = new Job();

            // Zusätzliche Felder, die nicht über den Binder gebunden sind, manuell setzen
            job.setPickupDate(pickupDate.getValue());
            job.setPickupTime(pickupTime.getValue());
            job.setDeliveryDate(deliveryDate.getValue());
            job.setDeliveryTime(deliveryTime.getValue());
            if (remarkArea != null)
                job.setRemark(remarkArea.getValue());

            // Store selected service IDs in job for invoice creation
            job.setServiceIds(selectedServices.stream().map(Service::getId).toList());

            // Validate all required fields using the binder
            if (binder.writeBeanIfValid(job)) {
                // Preis nach dem Binder-Call berechnen (damit er nicht überschrieben wird)
                Double routeDistance = getEffectiveRouteDistance();
                Integer durationSeconds = getEffectiveRouteDuration();
                BigDecimal netTotal = selectedServices.stream()
                        .map(s -> calculateServicePrice(s, routeDistance, durationSeconds))
                        .reduce(BigDecimal.ZERO, BigDecimal::add);
                job.setPrice(netTotal);
                
                // Store route distance and duration in job for invoice creation
                if (routeCalculationResult != null && routeCalculationResult.isValid()) {
                    // Berechnete Route verwenden
                    job.setRouteDistanceKm(routeCalculationResult.getDistanceKm());
                    job.setRouteDurationSeconds(routeCalculationResult.getDurationSeconds());
                } else if (manualDistanceInput != null && manualDistanceInput.getValue() != null) {
                    // Manuelle Eingabe verwenden
                    job.setRouteDistanceKm(manualDistanceInput.getValue());
                    if (manualDurationInput != null && manualDurationInput.getValue() != null) {
                        job.setRouteDurationSeconds(manualDurationInput.getValue() * 60); // Minuten in Sekunden umrechnen
                    }
                }
                // Additional validation: If digital processing is enabled, app user must be
                // selected
                if (digitalProcessing.getValue() && appUser.getValue() == null) {
                    Notification errorNotification = Notification.show(
                            "Wenn digitale Abwicklung per App aktiviert ist, muss ein App-Nutzer ausgewählt werden.");
                    errorNotification.setDuration(5000);
                    return;
                }

                // Ensure at least one cargo item is provided (tasks may be empty)
                // Definition: Ein Cargo-Item gilt nur als gefüllt, wenn eine Beschreibung
                // vorhanden ist
                List<CargoItem> cargoFilled = cargoItemsState.stream().filter(Objects::nonNull)
                        .filter(ci -> ci.getDescription() != null && !ci.getDescription().isBlank()).toList();

                if (cargoFilled.isEmpty()) {
                    Notification errorNotification = Notification
                            .show("Bitte fügen Sie mindestens eine Ladungszeile hinzu.");
                    errorNotification.setDuration(5000);
                    return;
                }
                // toggle cargo error highlight
                boolean hasCargo = true;
                cargoError.setVisible(!hasCargo);
                if (!hasCargo) {
                    cargoAreaContainer.getStyle().set("border", "1px solid var(--lumo-error-color-50pct)");
                } else {
                    cargoAreaContainer.getStyle().set("border", "1px solid var(--lumo-contrast-20pct)");
                }

                // NEU: Kunden anlegen, wenn Checkboxen aktiviert
                if (savePickupAddress.getValue()) {
                    Customer pickupCustomer = new Customer();
                    pickupCustomer.setCompanyName(pickupCompany.getValue());
                    pickupCustomer.setTitle(pickupSalutation.getValue());
                    pickupCustomer.setFirstname(pickupFirstName.getValue());
                    pickupCustomer.setLastName(pickupLastName.getValue());
                    pickupCustomer.setTelephone(pickupPhone.getValue());
                    pickupCustomer.setStreet(pickupStreet.getValue());
                    pickupCustomer.setHouseNumber(pickupHouseNumber.getValue());
                    pickupCustomer.setAddressAddition(pickupAddressAddition.getValue());
                    pickupCustomer.setZip(pickupZip.getValue());
                    pickupCustomer.setCity(pickupCity.getValue());
                    addCustomerService.addCustomer(pickupCustomer);
                }
                if (saveDeliveryAddress.getValue()) {
                    Customer deliveryCustomer = new Customer();
                    deliveryCustomer.setCompanyName(deliveryCompany.getValue());
                    deliveryCustomer.setTitle(deliverySalutation.getValue());
                    deliveryCustomer.setFirstname(deliveryFirstName.getValue());
                    deliveryCustomer.setLastName(deliveryLastName.getValue());
                    deliveryCustomer.setTelephone(deliveryPhone.getValue());
                    deliveryCustomer.setStreet(deliveryStreet.getValue());
                    deliveryCustomer.setHouseNumber(deliveryHouseNumber.getValue());
                    deliveryCustomer.setAddressAddition(deliveryAddressAddition.getValue());
                    deliveryCustomer.setZip(deliveryZip.getValue());
                    deliveryCustomer.setCity(deliveryCity.getValue());
                    addCustomerService.addCustomer(deliveryCustomer);
                }

                // All validations passed, save the job with cargo items and tasks
                // If digital processing is disabled, don't save any tasks
                List<BaseTask> tasksToSave = job.isDigitalProcessing() ? tasksState : List.of();
                Job savedJob = addJobService.addJobWithCargo(job, cargoFilled, tasksToSave);

                // Erfolgsmeldung und Navigation zur Zusammenfassung
                Notification successNotification = Notification
                        .show("Auftrag erfolgreich erstellt! Auftragsnummer: " + savedJob.getJobNumber());
                successNotification.setDuration(2000);
                getUI().ifPresent(ui -> ui.navigate(JobSummaryView.class, savedJob.getId().toHexString()));
            } else {
                // Validation failed, show error message
                Notification errorNotification = Notification
                        .show("Bitte füllen Sie alle Pflichtfelder aus (markiert mit *)");
                errorNotification.setDuration(5000);
            }

        } catch (Exception e) {
            // Other errors
            // Reset cargo error
            if (cargoError != null)
                cargoError.setVisible(false);
            if (cargoAreaContainer != null)
                cargoAreaContainer.getStyle().set("border", "1px solid var(--lumo-contrast-20pct)");
            Notification errorNotification = Notification.show("Fehler beim Erstellen des Auftrags: " + e.getMessage());
            errorNotification.setDuration(5000);
        }
    }

    // showSummary entfernt; Zusammenfassung als eigene Route

    // Zusammenfassungs-Helfer entfernt (Route übernimmt Darstellung)

    /**
     * Lädt verpflichtende Leistungen aus dem Leistungskatalog
     */
    private void loadMandatoryServices() {
        try {
            User currentUser = securityService.getCurrentDatabaseUser();
            if (currentUser != null) {
                List<Service> userServices = serviceRepository.findByUserId(currentUser.getId().toString());
                List<Service> mandatoryServices = userServices.stream().filter(Service::isMandatory).toList();

                if (!mandatoryServices.isEmpty()) {
                    selectedServices.addAll(mandatoryServices);
                    if (servicesGrid != null) {
                        servicesGrid.getDataProvider().refreshAll();
                    }
                    updatePriceSummary();
                    triggerValidation();
                    updateTabLabels();
                }
            }
        } catch (Exception e) {
            log.warn("Fehler beim Laden der verpflichtenden Leistungen: {}", e.getMessage());
        }
    }

    /**
     * Lädt einen bestehenden Entwurf, falls vorhanden
     */
    private void loadDraftIfExists() {
        try {
            String currentUser = getCurrentUsername();
            if (currentUser != null) {
                Optional<Job> draftOpt = addJobService.findCurrentDraft(currentUser);
                if (draftOpt.isPresent()) {
                    Job draft = draftOpt.get();
                    loadJobIntoForm(draft);

                    // Benutzer informieren
                    Notification notification = Notification
                            .show("Entwurf wiederhergestellt. Sie können Ihre Arbeit fortsetzen.");
                    notification.setDuration(4000);
                }
            }
        } catch (Exception e) {
            // Fehler beim Laden des Entwurfs sollten nicht die Anwendung blockieren
            log.warn("Fehler beim Laden des Entwurfs: {}", e.getMessage());
        }
    }

    /**
     * Lädt Job-Daten in das Formular
     */
    private void loadJobIntoForm(Job job) {
        if (job.getCustomerSelection() != null) {
            customerSelection.setValue(job.getCustomerSelection());
        }
    }

    private Component createCargoSection() {
        VerticalLayout wrapper = new VerticalLayout();
        wrapper.setWidthFull();
        wrapper.setSpacing(true);

        cargoAreaContainer = new VerticalLayout();
        cargoAreaContainer.setWidthFull();
        cargoAreaContainer.setSpacing(true);
        cargoAreaContainer.getStyle().set("background", "var(--lumo-base-color)");
        cargoAreaContainer.getStyle().set("border", "1px solid var(--lumo-contrast-20pct)");
        cargoAreaContainer.getStyle().set("border-radius", "var(--lumo-border-radius-m)");
        cargoAreaContainer.getStyle().set("padding", "var(--lumo-space-m)");

        H3 cargoTitle = new H3("Ladung");
        cargoError = new Span("Bitte fügen Sie mindestens eine Ladungszeile hinzu.");
        cargoError.getStyle().set("color", "var(--lumo-error-text-color)");
        cargoError.getStyle().set("font-size", "var(--lumo-font-size-s)");
        cargoError.setVisible(false);

        wrapper.add(cargoTitle);

        cargoList = new VerticalLayout();
        cargoList.setPadding(false);
        cargoList.setSpacing(true);
        cargoAreaContainer.add(cargoError, cargoList);

        java.util.function.BiConsumer<String, java.util.function.Consumer<HorizontalLayout>> addCargoRow = (iconName,
                afterCreate) -> {
            HorizontalLayout row = new HorizontalLayout();
            row.setWidthFull();
            row.setAlignItems(FlexComponent.Alignment.END);

            ComboBox<String> desc = new ComboBox<>("Beschreibung");
            desc.setItems("Europalette", "Einwegpalette", "Düsseldorfer-Palette", "Gitterboxpalette", "Gitterwagen",
                    "Paket");
            desc.setAllowCustomValue(true);
            desc.setPlaceholder("Wählen Sie eine Option oder geben Sie eigenen Text ein...");
            desc.setWidth("40%");
            desc.setRequiredIndicatorVisible(true);

            IntegerField qty = new IntegerField("Anzahl");
            qty.setMin(1);
            qty.setMax(9999); // Set reasonable maximum
            qty.setWidth("10%");
            qty.setRequiredIndicatorVisible(true);

            NumberField weight = new NumberField("Gewicht");
            weight.setSuffixComponent(new Span("kg"));
            weight.setWidth("15%");
            weight.setRequiredIndicatorVisible(true);

            NumberField len = new NumberField("Länge");
            len.setSuffixComponent(new Span("cm"));
            len.setWidth("12%");
            len.setRequiredIndicatorVisible(true);
            NumberField wid = new NumberField("Breite");
            wid.setSuffixComponent(new Span("cm"));
            wid.setWidth("12%");
            wid.setRequiredIndicatorVisible(true);
            NumberField hei = new NumberField("Höhe");
            hei.setSuffixComponent(new Span("cm"));
            hei.setWidth("12%");
            hei.setRequiredIndicatorVisible(true);

            Button remove = new Button(new Icon(VaadinIcon.CLOSE_SMALL));
            remove.addThemeVariants(ButtonVariant.LUMO_ERROR, ButtonVariant.LUMO_TERTIARY);
            remove.addClickListener(e -> {
                int idx = cargoList.getChildren().toList().indexOf(row);
                if (idx >= 0 && idx < cargoItemsState.size()) {
                    cargoItemsState.remove(idx);
                }
                cargoList.remove(row);
                triggerValidation();
                updateTabLabels();
            });

            row.add(desc, qty, weight, len, wid, hei, remove);
            cargoList.add(row);

            // Ensure backing list is in sync: add new item and bind change listeners
            CargoItem item = new CargoItem();
            cargoItemsState.add(item);

            // Initialize from current inputs
            item.setDescription(desc.getValue());
            item.setQuantity(qty.getValue());
            item.setWeightKg(weight.getValue());
            item.setLengthMm(len.getValue());
            item.setWidthMm(wid.getValue());
            item.setHeightMm(hei.getValue());

            // Validation helper to update field styling
            java.util.function.Consumer<com.vaadin.flow.component.HasValue<?, ?>> validateField = field -> {
                if (field instanceof ComboBox) {
                    ComboBox<?> combo = (ComboBox<?>) field;
                    String value = combo.getValue() != null ? combo.getValue().toString() : "";
                    combo.setInvalid(value.trim().isEmpty());
                } else if (field instanceof NumberField) {
                    NumberField numField = (NumberField) field;
                    numField.setInvalid(numField.getValue() == null || numField.getValue() <= 0);
                } else if (field instanceof IntegerField) {
                    IntegerField intField = (IntegerField) field;
                    boolean isInvalid = intField.getValue() == null || intField.getValue() <= 0;
                    intField.setInvalid(isInvalid);
                    if (isInvalid) {
                        intField.setErrorMessage("");
                        intField.getStyle().set("--vaadin-input-field-background", "rgba(255, 0, 0, 0.1)");
                        intField.getStyle().set("--vaadin-input-field-border-color", "rgba(255, 0, 0, 0.3)");
                    } else {
                        intField.setErrorMessage("");
                        intField.getStyle().remove("--vaadin-input-field-background");
                        intField.getStyle().remove("--vaadin-input-field-border-color");
                    }
                }
            };

            desc.addValueChangeListener(ev -> {
                item.setDescription(ev.getValue());
                validateField.accept(desc);
                triggerValidation();
                updateTabLabels();
            });
            qty.addValueChangeListener(ev -> {
                item.setQuantity(ev.getValue());
                validateField.accept(qty);
                triggerValidation();
                updateTabLabels();
            });
            weight.addValueChangeListener(ev -> {
                item.setWeightKg(ev.getValue());
                validateField.accept(weight);
                triggerValidation();
                updateTabLabels();
            });
            len.addValueChangeListener(ev -> {
                item.setLengthMm(ev.getValue());
                validateField.accept(len);
                triggerValidation();
                updateTabLabels();
            });
            wid.addValueChangeListener(ev -> {
                item.setWidthMm(ev.getValue());
                validateField.accept(wid);
                triggerValidation();
                updateTabLabels();
            });
            hei.addValueChangeListener(ev -> {
                item.setHeightMm(ev.getValue());
                validateField.accept(hei);
                triggerValidation();
                updateTabLabels();
            });

            // Initial validation
            validateField.accept(desc);
            validateField.accept(qty);
            validateField.accept(weight);
            validateField.accept(len);
            validateField.accept(wid);
            validateField.accept(hei);

            if (afterCreate != null)
                afterCreate.accept(row);
        };

        addCargoRow.accept("", r -> {
        }); // Show only one empty row by default

        // Add button to add more cargo rows
        Button addCargoButton = new Button("Ladung hinzufügen", new Icon(VaadinIcon.PLUS));
        addCargoButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        addCargoButton.setWidthFull(); // Make button full width of container
        addCargoButton.addClickListener(e -> addCargoRow.accept("", r -> {
        }));

        cargoAreaContainer.add(addCargoButton);
        wrapper.add(cargoAreaContainer);
        return wrapper;
    }

    private Component createTasksAndNotesSection() {
        VerticalLayout wrapper = new VerticalLayout();
        wrapper.setWidthFull();
        wrapper.setDefaultHorizontalComponentAlignment(FlexComponent.Alignment.CENTER);

        // Fester Content-Container für zentrierte Darstellung
        VerticalLayout content = new VerticalLayout();
        content.setWidth("720px");
        content.setPadding(false);
        content.setSpacing(true);
        content.setDefaultHorizontalComponentAlignment(FlexComponent.Alignment.STRETCH);

        // Aufgabentitel mit Template-Auswahl
        H3 tasksTitle = new H3("Zu quittierende Aufgaben");
        tasksTitle.getStyle().set("margin", "0");
        tasksTitle.getStyle().set("white-space", "nowrap");

        templateComboBox = new ComboBox<>();
        templateComboBox.setPlaceholder("Template auswählen...");
        templateComboBox.setItemLabelGenerator(TaskTemplate::getTemplateName);
        templateComboBox.setClearButtonVisible(true);
        // Breite auf verbleibenden Platz einstellen
        templateComboBox.setWidthFull();

        // Load templates for current user
        loadTemplatesIntoComboBox(templateComboBox);

        // Handle template selection
        templateComboBox.addValueChangeListener(e -> {
            if (e.getValue() != null) {
                loadTasksFromTemplate(e.getValue(), templateComboBox);
            }
        });

        // Icon-Button zum Speichern als Template
        Button saveAsTemplateBtn = new Button(new Icon(VaadinIcon.BOOKMARK));
        saveAsTemplateBtn.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
        saveAsTemplateBtn.setTooltipText("Aufgaben als Template speichern");
        saveAsTemplateBtn.addClickListener(e -> saveTasksAsTemplate());

        HorizontalLayout titleWithTemplate = new HorizontalLayout(tasksTitle, templateComboBox, saveAsTemplateBtn);
        titleWithTemplate.setAlignItems(FlexComponent.Alignment.CENTER);
        titleWithTemplate.setSpacing(true);
        content.add(titleWithTemplate);

        // Dynamische Aufgabenliste
        tasksList = new VerticalLayout();
        tasksList.setPadding(false);
        tasksList.setSpacing(true);

        java.util.function.Consumer<Void> addTask = (v) -> {
            createTaskRow();
        };

        // 1 Beispielzeile
        addTask.accept(null);

        Button addTaskBtn = new Button("Aufgabe hinzufügen", new Icon(VaadinIcon.PLUS));
        addTaskBtn.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        addTaskBtn.addClickListener(e -> addTask.accept(null));

        content.add(tasksList, addTaskBtn);

        // Bemerkung
        H3 remarksTitle = new H3("Bemerkung");
        remarksTitle.getStyle().set("margin", "0");
        remarkArea = new TextArea();
        remarkArea.setPlaceholder("z.B. rückwärtigen Liefereingang benutzen o. ä.");
        remarkArea.setWidthFull();
        remarkArea.setMinHeight("180px");
        content.add(remarksTitle, remarkArea);

        wrapper.add(content);
        return wrapper;
    }

    /**
     * Hilfsmethode zum Abrufen des aktuellen Benutzernamens
     */
    private String getCurrentUsername() {
        try {
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            if (authentication != null && authentication.isAuthenticated()
                    && !"anonymousUser".equals(authentication.getPrincipal())) {
                return authentication.getName();
            }
            return null;
        } catch (Exception e) {
            log.warn("Fehler beim Auslesen des aktuellen Benutzers: {}", e.getMessage());
            return null;
        }
    }

    /**
     * Leert alle Felder im Formular
     */
    private void clearAllFields() {
        // Streckeninformationen zurücksetzen
        resetRouteInformation();

        // Customer selection
        customerSelection.clear();

        // Pickup address
        pickupCompany.clear();
        pickupSalutation.clear();
        pickupFirstName.clear();
        pickupLastName.clear();
        pickupPhone.clear();
        pickupStreet.clear();
        pickupHouseNumber.clear();
        pickupAddressAddition.clear();
        pickupZip.clear();
        pickupCity.clear();
        savePickupAddress.setValue(false);

        // Delivery address
        deliveryCompany.clear();
        deliverySalutation.clear();
        deliveryFirstName.clear();
        deliveryLastName.clear();
        deliveryPhone.clear();
        deliveryStreet.clear();
        deliveryHouseNumber.clear();
        deliveryAddressAddition.clear();
        deliveryZip.clear();
        deliveryCity.clear();
        saveDeliveryAddress.setValue(false);

        // Digital processing
        digitalProcessing.setValue(true);
        appUser.clear();

        // Clear services
        selectedServices.clear();
        if (servicesGrid != null) {
            servicesGrid.getDataProvider().refreshAll();
        }
        updatePriceSummary();

        // Benutzer-Feedback
        Notification.show("Alle Felder wurden geleert", 2000, Notification.Position.BOTTOM_CENTER);
    }

    /**
     * Konfiguriert Focus-Listener für alle Eingabefelder um Drag-and-Drop zu
     * steuern
     */
    private void setupInputFieldFocusListeners() {
        // Customer selection
        customerSelection.addFocusListener(e -> disableDragSources());
        customerSelection.addBlurListener(e -> enableDragSources());

        // Pickup fields
        pickupCompany.addFocusListener(e -> disableDragSources());
        pickupCompany.addBlurListener(e -> enableDragSources());
        pickupSalutation.addFocusListener(e -> disableDragSources());
        pickupSalutation.addBlurListener(e -> enableDragSources());
        pickupFirstName.addFocusListener(e -> disableDragSources());
        pickupFirstName.addBlurListener(e -> enableDragSources());
        pickupLastName.addFocusListener(e -> disableDragSources());
        pickupLastName.addBlurListener(e -> enableDragSources());
        pickupPhone.addFocusListener(e -> disableDragSources());
        pickupPhone.addBlurListener(e -> enableDragSources());
        pickupStreet.addFocusListener(e -> disableDragSources());
        pickupStreet.addBlurListener(e -> enableDragSources());
        pickupHouseNumber.addFocusListener(e -> disableDragSources());
        pickupHouseNumber.addBlurListener(e -> enableDragSources());
        pickupAddressAddition.addFocusListener(e -> disableDragSources());
        pickupAddressAddition.addBlurListener(e -> enableDragSources());
        pickupZip.addFocusListener(e -> disableDragSources());
        pickupZip.addBlurListener(e -> enableDragSources());
        pickupCity.addFocusListener(e -> disableDragSources());
        pickupCity.addBlurListener(e -> enableDragSources());

        // Delivery fields
        deliveryCompany.addFocusListener(e -> disableDragSources());
        deliveryCompany.addBlurListener(e -> enableDragSources());
        deliverySalutation.addFocusListener(e -> disableDragSources());
        deliverySalutation.addBlurListener(e -> enableDragSources());
        deliveryFirstName.addFocusListener(e -> disableDragSources());
        deliveryFirstName.addBlurListener(e -> enableDragSources());
        deliveryLastName.addFocusListener(e -> disableDragSources());
        deliveryLastName.addBlurListener(e -> enableDragSources());
        deliveryPhone.addFocusListener(e -> disableDragSources());
        deliveryPhone.addBlurListener(e -> enableDragSources());
        deliveryStreet.addFocusListener(e -> disableDragSources());
        deliveryStreet.addBlurListener(e -> enableDragSources());
        deliveryHouseNumber.addFocusListener(e -> disableDragSources());
        deliveryHouseNumber.addBlurListener(e -> enableDragSources());
        deliveryAddressAddition.addFocusListener(e -> disableDragSources());
        deliveryAddressAddition.addBlurListener(e -> enableDragSources());
        deliveryZip.addFocusListener(e -> disableDragSources());
        deliveryZip.addBlurListener(e -> enableDragSources());
        deliveryCity.addFocusListener(e -> disableDragSources());
        deliveryCity.addBlurListener(e -> enableDragSources());

        // Digital processing
        appUser.addFocusListener(e -> disableDragSources());
        appUser.addBlurListener(e -> enableDragSources());
    }

    /**
     * Deaktiviert alle Drag-Sources durch CSS
     */
    private void disableDragSources() {
        if (pickupSection != null) {
            pickupSection.getStyle().set("pointer-events", "none");
            pickupSection.getElement().setAttribute("draggable", "false");
        }
        if (deliverySection != null) {
            deliverySection.getStyle().set("pointer-events", "none");
            deliverySection.getElement().setAttribute("draggable", "false");
        }
    }

    /**
     * Aktiviert alle Drag-Sources durch CSS
     */
    private void enableDragSources() {
        if (pickupSection != null) {
            pickupSection.getStyle().remove("pointer-events");
            pickupSection.getElement().setAttribute("draggable", "true");
        }
        if (deliverySection != null) {
            deliverySection.getStyle().remove("pointer-events");
            deliverySection.getElement().setAttribute("draggable", "true");
        }
    }

    private void createTaskRow() {
        VerticalLayout taskContainer = new VerticalLayout();
        taskContainer.setPadding(true);
        taskContainer.setSpacing(true);
        taskContainer.getStyle().set("border", "1px solid var(--lumo-contrast-20pct)");
        taskContainer.getStyle().set("border-radius", "var(--lumo-border-radius-m)");
        taskContainer.getStyle().set("background-color", "var(--lumo-base-color)");
        taskContainer.getStyle().set("position", "relative");

        // Task type selection
        ComboBox<TaskType> taskTypeCombo = new ComboBox<>("Aufgabentyp");
        taskTypeCombo.setItems(TaskType.values());
        taskTypeCombo.setItemLabelGenerator(TaskType::getDisplayName);
        taskTypeCombo.setPlaceholder("Aufgabentyp wählen...");
        taskTypeCombo.setWidthFull();

        // Configuration container for dynamic fields
        VerticalLayout configContainer = new VerticalLayout();
        configContainer.setPadding(false);
        configContainer.setSpacing(true);

        // Red X button positioned in top-right corner
        Button deleteXButton = new Button(new Icon(VaadinIcon.CLOSE_SMALL));
        deleteXButton.addThemeVariants(ButtonVariant.LUMO_ERROR, ButtonVariant.LUMO_TERTIARY);
        deleteXButton.getStyle().set("position", "absolute");
        deleteXButton.getStyle().set("top", "8px");
        deleteXButton.getStyle().set("right", "8px");
        deleteXButton.getStyle().set("z-index", "10");
        deleteXButton.getStyle().set("padding", "4px");
        deleteXButton.getStyle().set("min-width", "24px");
        deleteXButton.getStyle().set("min-height", "24px");
        deleteXButton.addClickListener(e -> {
            int idx = tasksList.getChildren().toList().indexOf(taskContainer);
            if (idx >= 0 && idx < tasksState.size()) {
                tasksState.remove(idx);
                // Reorder remaining tasks to maintain correct sequence
                reorderTasksAfterDeletion();
            }
            tasksList.remove(taskContainer);
        });

        taskContainer.add(taskTypeCombo, configContainer);
        taskContainer.add(deleteXButton);

        // Create Task and add to state with correct order
        BaseTask task = new ConfirmationTask("");
        task.setTaskOrder(tasksState.size()); // Set order based on current position
        tasksState.add(task);

        // Use an array to hold the current task reference (allows modification in
        // lambda)
        final BaseTask[] currentTask = { task };

        taskTypeCombo.addValueChangeListener(ev -> {
            TaskType selectedType = ev.getValue();
            if (selectedType != null) {
                // Create new task instance based on type
                BaseTask newTask = createTaskByType(selectedType);
                BaseTask oldTask = currentTask[0];

                newTask.setDescription(oldTask.getDescription());
                newTask.setCompleted(oldTask.isCompleted());
                newTask.setCompletedAt(oldTask.getCompletedAt());
                newTask.setCompletedBy(oldTask.getCompletedBy());

                // Preserve task-specific properties
                switch (oldTask) {
                case ConfirmationTask oldConfirmationTask when newTask instanceof ConfirmationTask newConfirmationTask ->
                    newConfirmationTask.setButtonText(oldConfirmationTask.getButtonText());
                case TodoListTask oldTodoTask when newTask instanceof TodoListTask newTodoTask ->
                    newTodoTask.setTodoItems(oldTodoTask.getTodoItems());
                case PhotoTask oldPhotoTask when newTask instanceof PhotoTask newPhotoTask -> {
                    newPhotoTask.setMinPhotoCount(oldPhotoTask.getMinPhotoCount());
                    newPhotoTask.setMaxPhotoCount(oldPhotoTask.getMaxPhotoCount());
                }
                case BarcodeTask oldBarcodeTask when newTask instanceof BarcodeTask newBarcodeTask -> {
                    newBarcodeTask.setMinBarcodeCount(oldBarcodeTask.getMinBarcodeCount());
                    newBarcodeTask.setMaxBarcodeCount(oldBarcodeTask.getMaxBarcodeCount());
                }
                case CommentTask oldCommentTask when newTask instanceof CommentTask newCommentTask -> {
                    newCommentTask.setCommentText(oldCommentTask.getCommentText());
                    newCommentTask.setRequired(oldCommentTask.isRequired());
                }
                default -> {
                }
                }

                // Replace in state and preserve order
                int index = tasksState.indexOf(oldTask);
                if (index >= 0) {
                    newTask.setTaskOrder(index); // Preserve the order
                    tasksState.set(index, newTask);
                    currentTask[0] = newTask; // Update the reference
                }

                updateTaskConfiguration(configContainer, newTask);
                triggerValidation();
                updateTabLabels();
            }
        });

        // Set initial configuration
        taskTypeCombo.setValue(TaskType.CONFIRMATION);
        updateTaskConfiguration(configContainer, currentTask[0]);
        triggerValidation();
        updateTabLabels();

        tasksList.add(taskContainer);
    }

    private BaseTask createTaskByType(TaskType taskType) {
        return switch (taskType) {
        case CONFIRMATION -> new ConfirmationTask("");
        case SIGNATURE -> new SignatureTask();
        case TODOLIST -> new TodoListTask(new ArrayList<>());
        case PHOTO -> new PhotoTask(1, 10);
        case BARCODE -> new BarcodeTask(1, 10);
        case COMMENT -> new CommentTask("", false);
        };
    }

    private void reorderTasksAfterDeletion() {
        // Reorder all tasks in tasksState to maintain correct sequence
        for (int i = 0; i < tasksState.size(); i++) {
            BaseTask task = tasksState.get(i);
            if (task != null) {
                task.setTaskOrder(i); // Reset order to match current position
            }
        }
    }

    private void updateTaskConfiguration(VerticalLayout configContainer, BaseTask task) {
        configContainer.removeAll();

        TaskType taskType = TaskType.valueOf(task.getTaskType());

        switch (taskType) {
        case CONFIRMATION:
            // Description field (required)
            TextField descriptionField = new TextField("Beschreibung");
            descriptionField.setPlaceholder("Beschreibung der Aufgabe...");
            descriptionField.setWidthFull();
            descriptionField.setRequiredIndicatorVisible(true);
            descriptionField.setValue(task.getDescription() != null ? task.getDescription() : "");
            descriptionField.addValueChangeListener(ev -> {
                task.setDescription(ev.getValue());
                // Update field styling based on value
                boolean isEmpty = ev.getValue() == null || ev.getValue().trim().isEmpty();
                if (isEmpty) {
                    descriptionField.getStyle().set("--vaadin-input-field-background", "rgba(255, 0, 0, 0.1)");
                    descriptionField.getStyle().set("--vaadin-input-field-border-color", "rgba(255, 0, 0, 0.3)");
                } else {
                    descriptionField.getStyle().remove("--vaadin-input-field-background");
                    descriptionField.getStyle().remove("--vaadin-input-field-border-color");
                }
                triggerValidation();
                updateTabLabels();
            });
            // Initial styling for empty field
            if (task.getDescription() == null || task.getDescription().trim().isEmpty()) {
                descriptionField.getStyle().set("--vaadin-input-field-background", "rgba(255, 0, 0, 0.1)");
                descriptionField.getStyle().set("--vaadin-input-field-border-color", "rgba(255, 0, 0, 0.3)");
            }

            // Button text field (required)
            TextField buttonTextField = new TextField("Button-Text");
            buttonTextField.setPlaceholder("z.B. 'Bestätigen', 'Abgeschlossen'");
            buttonTextField.setWidthFull();
            buttonTextField.setRequiredIndicatorVisible(true);
            ConfirmationTask confirmationTask = (ConfirmationTask) task;
            buttonTextField.setValue(confirmationTask.getButtonText() != null ? confirmationTask.getButtonText() : "");
            buttonTextField.addValueChangeListener(ev -> {
                // Find the current ConfirmationTask in tasksState and update it
                for (BaseTask stateTask : tasksState) {
                    if (stateTask instanceof ConfirmationTask) {
                        ((ConfirmationTask) stateTask).setButtonText(ev.getValue());
                    }
                }
                // Update field styling based on value
                boolean isEmpty = ev.getValue() == null || ev.getValue().trim().isEmpty();
                if (isEmpty) {
                    buttonTextField.getStyle().set("--vaadin-input-field-background", "rgba(255, 0, 0, 0.1)");
                    buttonTextField.getStyle().set("--vaadin-input-field-border-color", "rgba(255, 0, 0, 0.3)");
                } else {
                    buttonTextField.getStyle().remove("--vaadin-input-field-background");
                    buttonTextField.getStyle().remove("--vaadin-input-field-border-color");
                }
                triggerValidation();
                updateTabLabels();
            });
            // Initial styling for empty field
            if (confirmationTask.getButtonText() == null || confirmationTask.getButtonText().trim().isEmpty()) {
                buttonTextField.getStyle().set("--vaadin-input-field-background", "rgba(255, 0, 0, 0.1)");
                buttonTextField.getStyle().set("--vaadin-input-field-border-color", "rgba(255, 0, 0, 0.3)");
            }
            configContainer.add(descriptionField, buttonTextField);
            break;

        case SIGNATURE:
            // No additional configuration needed
            Span info = new Span("Keine zusätzliche Konfiguration erforderlich");
            info.getStyle().set("color", "var(--lumo-secondary-text-color)");
            info.getStyle().set("font-style", "italic");
            configContainer.add(info);
            break;

        case TODOLIST:
            VerticalLayout todoContainer = new VerticalLayout();
            todoContainer.setPadding(false);
            todoContainer.setSpacing(true);

            H3 todoTitle = new H3("To-Do Punkte");
            todoTitle.getStyle().set("margin", "0");
            todoContainer.add(todoTitle);

            // Dynamic todo list
            VerticalLayout todoList = new VerticalLayout();
            todoList.setPadding(false);
            todoList.setSpacing(true);

            // Helper to update todo field styling based on value
            java.util.function.Consumer<TextField> updateTodoFieldStyling = (field) -> {
                boolean isEmpty = field.getValue() == null || field.getValue().trim().isEmpty();
                if (isEmpty) {
                    field.getStyle().set("--vaadin-input-field-background", "rgba(255, 0, 0, 0.1)");
                    field.getStyle().set("--vaadin-input-field-border-color", "rgba(255, 0, 0, 0.3)");
                } else {
                    field.getStyle().remove("--vaadin-input-field-background");
                    field.getStyle().remove("--vaadin-input-field-border-color");
                }
            };

            java.util.function.Consumer<Void> addTodoItem = (v) -> {
                HorizontalLayout todoRow = new HorizontalLayout();
                todoRow.setWidthFull();
                todoRow.setAlignItems(FlexComponent.Alignment.END);

                TextField todoField = new TextField();
                todoField.setPlaceholder("To-Do Punkt");
                todoField.setWidth("100%");
                todoField.setRequiredIndicatorVisible(true);
                // Initial red styling for empty field
                updateTodoFieldStyling.accept(todoField);

                Button removeTodo = new Button(new Icon(VaadinIcon.CLOSE_SMALL));
                removeTodo.addThemeVariants(ButtonVariant.LUMO_ERROR, ButtonVariant.LUMO_TERTIARY);
                removeTodo.addClickListener(e -> {
                    todoList.remove(todoRow);
                    updateTodoItems(todoList, task);
                });

                todoRow.add(todoField, removeTodo);
                todoRow.setFlexGrow(1, todoField);
                todoList.add(todoRow);

                todoField.addValueChangeListener(ev -> {
                    updateTodoFieldStyling.accept(todoField);
                    updateTodoItems(todoList, task);
                });
            };

            Button addTodoBtn = new Button("To-Do Punkt hinzufügen", new Icon(VaadinIcon.PLUS));
            addTodoBtn.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
            addTodoBtn.addClickListener(e -> addTodoItem.accept(null));

            // Load existing todo items from the task, or add one empty item if none exist
            if (task instanceof TodoListTask) {
                TodoListTask todoTask = (TodoListTask) task;
                if (todoTask.getTodoItems() != null && !todoTask.getTodoItems().isEmpty()) {
                    // Create UI rows for existing todo items
                    for (String todoText : todoTask.getTodoItems()) {
                        HorizontalLayout todoRow = new HorizontalLayout();
                        todoRow.setWidthFull();
                        todoRow.setAlignItems(FlexComponent.Alignment.END);

                        TextField todoField = new TextField();
                        todoField.setPlaceholder("To-Do Punkt");
                        todoField.setWidth("100%");
                        todoField.setRequiredIndicatorVisible(true);
                        todoField.setValue(todoText != null ? todoText : ""); // Set the saved text
                        // Apply styling based on value
                        updateTodoFieldStyling.accept(todoField);

                        Button removeTodo = new Button(new Icon(VaadinIcon.CLOSE_SMALL));
                        removeTodo.addThemeVariants(ButtonVariant.LUMO_ERROR, ButtonVariant.LUMO_TERTIARY);
                        removeTodo.addClickListener(e -> {
                            todoList.remove(todoRow);
                            updateTodoItems(todoList, task);
                        });

                        todoRow.add(todoField, removeTodo);
                        todoRow.setFlexGrow(1, todoField);
                        todoList.add(todoRow);

                        todoField.addValueChangeListener(ev -> {
                            updateTodoFieldStyling.accept(todoField);
                            updateTodoItems(todoList, task);
                        });
                    }
                } else {
                    // Add initial empty todo item if no existing items
                    addTodoItem.accept(null);
                }
            } else {
                // Add initial empty todo item for new tasks
                addTodoItem.accept(null);
            }

            todoContainer.add(todoList, addTodoBtn);
            configContainer.add(todoContainer);
            break;

        case PHOTO:
            HorizontalLayout photoLayout = new HorizontalLayout();
            photoLayout.setWidthFull();
            photoLayout.setSpacing(true);

            PhotoTask photoTask = (PhotoTask) task;
            IntegerField minPhotos = new IntegerField("Min. Anzahl Fotos");
            minPhotos.setPlaceholder("1");
            minPhotos.setMin(1);
            minPhotos.setValue(photoTask.getMinPhotoCount() != null ? photoTask.getMinPhotoCount() : 1);

            IntegerField maxPhotos = new IntegerField("Max. Anzahl Fotos");
            maxPhotos.setPlaceholder("10");
            maxPhotos.setMin(1);
            maxPhotos.setValue(photoTask.getMaxPhotoCount() != null ? photoTask.getMaxPhotoCount() : 10);

            photoLayout.add(minPhotos, maxPhotos);

            minPhotos.addValueChangeListener(ev -> {
                photoTask.setMinPhotoCount(ev.getValue());
            });

            maxPhotos.addValueChangeListener(ev -> {
                photoTask.setMaxPhotoCount(ev.getValue());
            });

            configContainer.add(photoLayout);
            break;

        case BARCODE:
            HorizontalLayout barcodeLayout = new HorizontalLayout();
            barcodeLayout.setWidthFull();
            barcodeLayout.setSpacing(true);

            BarcodeTask barcodeTask = (BarcodeTask) task;
            IntegerField minBarcodes = new IntegerField("Min. Anzahl Barcodes");
            minBarcodes.setPlaceholder("1");
            minBarcodes.setMin(1);
            minBarcodes.setValue(barcodeTask.getMinBarcodeCount() != null ? barcodeTask.getMinBarcodeCount() : 1);

            IntegerField maxBarcodes = new IntegerField("Max. Anzahl Barcodes");
            maxBarcodes.setPlaceholder("10");
            maxBarcodes.setMin(1);
            maxBarcodes.setValue(barcodeTask.getMaxBarcodeCount() != null ? barcodeTask.getMaxBarcodeCount() : 10);

            barcodeLayout.add(minBarcodes, maxBarcodes);

            minBarcodes.addValueChangeListener(ev -> {
                barcodeTask.setMinBarcodeCount(ev.getValue());
            });

            maxBarcodes.addValueChangeListener(ev -> {
                barcodeTask.setMaxBarcodeCount(ev.getValue());
            });

            configContainer.add(barcodeLayout);
            break;

        case COMMENT:
            CommentTask commentTask = (CommentTask) task;

            TextField commentTextField = new TextField("Kommentar-Platzhalter");
            commentTextField.setPlaceholder("Hinweis für den Benutzer...");
            commentTextField.setWidthFull();
            commentTextField.setValue(commentTask.getCommentText() != null ? commentTask.getCommentText() : "");
            commentTextField.addValueChangeListener(ev -> {
                commentTask.setCommentText(ev.getValue());
            });

            com.vaadin.flow.component.checkbox.Checkbox requiredCheckbox = new com.vaadin.flow.component.checkbox.Checkbox(
                    "Pflichtfeld");
            requiredCheckbox.setValue(commentTask.isRequired());
            requiredCheckbox.addValueChangeListener(ev -> {
                commentTask.setRequired(ev.getValue());
            });

            configContainer.add(commentTextField, requiredCheckbox);
            break;

        default:
            throw new IllegalArgumentException("Unbekannter TaskType: " + taskType);
        }
    }

    private void updateTodoItems(VerticalLayout todoList, BaseTask task) {
        List<String> todoItems = todoList.getChildren().map(component -> {
            if (component instanceof HorizontalLayout row) {
                TextField field = (TextField) row.getChildren().findFirst().orElse(null);
                return field != null ? field.getValue() : null;
            }
            return null;
        }).filter(Objects::nonNull).filter(item -> !item.trim().isEmpty())
                .collect(java.util.stream.Collectors.toList());

        if (task instanceof TodoListTask) {
            ((TodoListTask) task).setTodoItems(todoItems);
        }

        // Trigger validation to update submit button state
        triggerValidation();
        updateTabLabels();
    }

    /**
     * Speichert die aktuell konfigurierten Aufgaben als Template
     */
    private void saveTasksAsTemplate() {
        try {
            // Check if there are any tasks to save
            if (tasksState.isEmpty()) {
                Notification.show("Keine Aufgaben zum Speichern vorhanden", 3000, Notification.Position.BOTTOM_END);
                return;
            }

            // Create dialog for template name input
            Dialog dialog = new Dialog();
            dialog.setHeaderTitle("Template speichern");
            dialog.setWidth("400px");

            VerticalLayout dialogLayout = new VerticalLayout();
            dialogLayout.setPadding(false);
            dialogLayout.setSpacing(true);

            TextField templateNameField = new TextField("Template-Name");
            templateNameField.setPlaceholder("Geben Sie einen Namen für das Template ein");
            templateNameField.setWidthFull();
            templateNameField.setRequiredIndicatorVisible(true);

            Button saveButton = new Button("Speichern");
            saveButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
            saveButton.addClickListener(e -> {
                String templateName = templateNameField.getValue();
                if (templateName == null || templateName.trim().isEmpty()) {
                    Notification.show("Bitte geben Sie einen Template-Namen ein", 3000,
                            Notification.Position.BOTTOM_END);
                    return;
                }

                try {
                    // Create deep copies of current tasks
                    List<BaseTask> tasksCopy = new ArrayList<>();
                    for (BaseTask task : tasksState) {
                        // Create a copy of each task to avoid reference issues
                        BaseTask taskCopy = createTaskCopy(task);
                        tasksCopy.add(taskCopy);
                    }

                    // Save template with task type information and specific data
                    taskTemplateService.createTemplate(securityService.getCurrentDatabaseUser().getId(),
                            templateName.trim(), tasksCopy);

                    dialog.close();
                    loadTemplatesIntoComboBox(templateComboBox);
                    Notification.show("Template '" + templateName + "' erfolgreich gespeichert", 3000,
                            Notification.Position.BOTTOM_END);

                } catch (RuntimeException ex) {
                    Notification.show(ex.getMessage(), 4000, Notification.Position.MIDDLE);
                } catch (Exception ex) {
                    log.error("Error saving task template", ex);
                    Notification.show("Fehler beim Speichern des Templates: " + ex.getMessage(), 4000,
                            Notification.Position.MIDDLE);
                }
            });

            Button cancelButton = new Button("Abbrechen");
            cancelButton.addClickListener(e -> dialog.close());

            HorizontalLayout buttonLayout = new HorizontalLayout(cancelButton, saveButton);
            buttonLayout.setJustifyContentMode(FlexComponent.JustifyContentMode.END);

            dialogLayout.add(templateNameField, buttonLayout);
            dialog.add(dialogLayout);
            dialog.open();

        } catch (Exception e) {
            log.error("Error opening save template dialog", e);
            Notification.show("Fehler beim Öffnen des Dialogs: " + e.getMessage(), 4000, Notification.Position.MIDDLE);
        }
    }

    /**
     * Creates a deep copy of a task to avoid reference issues in templates Saves
     * all task-specific data including type and specific properties
     */
    private BaseTask createTaskCopy(BaseTask original) {
        BaseTask copy = null;

        if (original instanceof ConfirmationTask) {
            ConfirmationTask origTask = (ConfirmationTask) original;
            copy = new ConfirmationTask();
            // Copy all specific data for ConfirmationTask
            if (origTask.getButtonText() != null) {
                ((ConfirmationTask) copy).setButtonText(origTask.getButtonText());
            }
        } else if (original instanceof SignatureTask) {
            // SignatureTask has no specific data beyond the base task
            copy = new SignatureTask();
        } else if (original instanceof TodoListTask) {
            TodoListTask origTask = (TodoListTask) original;
            copy = new TodoListTask();
            // Copy all todo items
            if (origTask.getTodoItems() != null) {
                ((TodoListTask) copy).setTodoItems(new ArrayList<>(origTask.getTodoItems()));
            }
        } else if (original instanceof PhotoTask) {
            PhotoTask origTask = (PhotoTask) original;
            // Copy with all photo-specific parameters
            copy = new PhotoTask(origTask.getMinPhotoCount() != null ? origTask.getMinPhotoCount() : 1,
                    origTask.getMaxPhotoCount() != null ? origTask.getMaxPhotoCount() : 10);
        } else if (original instanceof BarcodeTask) {
            BarcodeTask origTask = (BarcodeTask) original;
            // Copy with all barcode-specific parameters
            copy = new BarcodeTask(origTask.getMinBarcodeCount() != null ? origTask.getMinBarcodeCount() : 1,
                    origTask.getMaxBarcodeCount() != null ? origTask.getMaxBarcodeCount() : 10);
        } else if (original instanceof CommentTask) {
            CommentTask origTask = (CommentTask) original;
            // Copy with all comment-specific parameters
            copy = new CommentTask(origTask.getCommentText() != null ? origTask.getCommentText() : "",
                    origTask.isRequired());
        }

        if (copy != null) {
            // Copy all base task properties
            copy.setDescription(original.getDescription());
            copy.setTaskOrder(original.getTaskOrder() != null ? original.getTaskOrder() : 0);
            copy.setCompleted(original.isCompleted());
            copy.setCompletedAt(original.getCompletedAt());
            copy.setCompletedBy(original.getCompletedBy());
        }

        return copy;
    }

    /**
     * Loads available templates into the ComboBox
     */
    private void loadTemplatesIntoComboBox(ComboBox<TaskTemplate> templateComboBox) {
        try {
            List<TaskTemplate> templates = taskTemplateService
                    .findByUserId(securityService.getCurrentDatabaseUser().getId());
            templateComboBox.setItems(templates);
        } catch (Exception e) {
            log.error("Error loading templates", e);
            Notification.show("Fehler beim Laden der Templates: " + e.getMessage(), 4000, Notification.Position.MIDDLE);
        }
    }

    /**
     * Loads tasks from selected template with confirmation dialog
     */
    private void loadTasksFromTemplate(TaskTemplate template, ComboBox<TaskTemplate> templateComboBox) {
        ConfirmDialog confirmDialog = new ConfirmDialog();
        confirmDialog.setHeader("Template laden");
        confirmDialog.setText("Möchten Sie wirklich das Template '" + template.getTemplateName()
                + "' laden? Alle aktuellen Aufgaben werden ersetzt.");
        confirmDialog.setCancelable(true);
        confirmDialog.setCancelText("Abbrechen");
        confirmDialog.setConfirmText("Laden");
        confirmDialog.setConfirmButtonTheme("primary");

        confirmDialog.addConfirmListener(e -> {
            try {
                // Clear current tasks
                tasksState.clear();
                tasksList.removeAll();

                // Add tasks from template
                if (template.getTasks() != null) {
                    for (BaseTask templateTask : template.getTasks()) {
                        BaseTask taskCopy = createTaskCopy(templateTask);
                        if (taskCopy != null) {
                            tasksState.add(taskCopy);
                            createTaskRowFromTask(taskCopy);
                        }
                    }
                }

                // Clear the combobox selection
                templateComboBox.clear();

                // Re-validate to enable submit button if all fields are valid
                triggerValidation();
                updateTabLabels();

                Notification.show("Template '" + template.getTemplateName() + "' erfolgreich geladen", 3000,
                        Notification.Position.BOTTOM_END);

            } catch (Exception ex) {
                log.error("Error loading template tasks", ex);
                Notification.show("Fehler beim Laden des Templates: " + ex.getMessage(), 4000,
                        Notification.Position.MIDDLE);
            }
        });

        confirmDialog.addCancelListener(e -> {
            // Clear the combobox selection if user cancels
            templateComboBox.clear();
        });

        confirmDialog.open();
    }

    /**
     * Creates a task row from an existing task (used when loading templates) This
     * creates a UI row and populates it with the task's specific data
     */
    private void createTaskRowFromTask(BaseTask task) {
        // Don't call createTaskRow() directly, as it would create a default
        // ConfirmationTask
        // Instead, create the UI components and set them up with the loaded task

        VerticalLayout taskContainer = new VerticalLayout();
        taskContainer.setPadding(true);
        taskContainer.setSpacing(true);
        taskContainer.getStyle().set("border", "1px solid var(--lumo-contrast-20pct)");
        taskContainer.getStyle().set("border-radius", "var(--lumo-border-radius-m)");
        taskContainer.getStyle().set("background-color", "var(--lumo-base-color)");
        taskContainer.getStyle().set("position", "relative");

        // Task type selection
        ComboBox<TaskType> taskTypeCombo = new ComboBox<>("Aufgabentyp");
        taskTypeCombo.setItems(TaskType.values());
        taskTypeCombo.setItemLabelGenerator(TaskType::getDisplayName);
        taskTypeCombo.setPlaceholder("Aufgabentyp wählen...");
        taskTypeCombo.setWidthFull();

        // Configuration container for dynamic fields
        VerticalLayout configContainer = new VerticalLayout();
        configContainer.setPadding(false);
        configContainer.setSpacing(true);

        // Red X button positioned in top-right corner
        Button deleteXButton = new Button(new Icon(VaadinIcon.CLOSE_SMALL));
        deleteXButton.addThemeVariants(ButtonVariant.LUMO_ERROR, ButtonVariant.LUMO_TERTIARY);
        deleteXButton.getStyle().set("position", "absolute");
        deleteXButton.getStyle().set("top", "8px");
        deleteXButton.getStyle().set("right", "8px");
        deleteXButton.getStyle().set("z-index", "10");
        deleteXButton.getStyle().set("padding", "4px");
        deleteXButton.getStyle().set("min-width", "24px");
        deleteXButton.getStyle().set("min-height", "24px");
        deleteXButton.addClickListener(e -> {
            int idx = tasksList.getChildren().toList().indexOf(taskContainer);
            if (idx >= 0 && idx < tasksState.size()) {
                tasksState.remove(idx);
                reorderTasksAfterDeletion();
            }
            tasksList.remove(taskContainer);
        });

        taskContainer.add(taskTypeCombo, configContainer);
        taskContainer.add(deleteXButton);

        final BaseTask[] currentTask = { task };

        // Set the combo value BEFORE registering the listener so the listener does
        // NOT fire during initialization. The loaded task object is already correct
        // and is already in tasksState — no replacement needed.
        TaskType taskType = getTaskTypeFromTask(task);
        if (taskType != null) {
            taskTypeCombo.setValue(taskType);
        }

        // Register the listener for user-initiated type changes only
        taskTypeCombo.addValueChangeListener(ev -> {
            TaskType selectedType = ev.getValue();
            if (selectedType != null) {
                BaseTask newTask = createTaskByType(selectedType);
                BaseTask oldTask = currentTask[0];

                newTask.setDescription(oldTask.getDescription());
                newTask.setCompleted(oldTask.isCompleted());
                newTask.setCompletedAt(oldTask.getCompletedAt());
                newTask.setCompletedBy(oldTask.getCompletedBy());

                // Preserve task-specific properties
                switch (oldTask) {
                case ConfirmationTask oldConfirmationTask when newTask instanceof ConfirmationTask newConfirmationTask ->
                    newConfirmationTask.setButtonText(oldConfirmationTask.getButtonText());
                case TodoListTask oldTodoTask when newTask instanceof TodoListTask newTodoTask ->
                    newTodoTask.setTodoItems(oldTodoTask.getTodoItems());
                case PhotoTask oldPhotoTask when newTask instanceof PhotoTask newPhotoTask -> {
                    newPhotoTask.setMinPhotoCount(oldPhotoTask.getMinPhotoCount());
                    newPhotoTask.setMaxPhotoCount(oldPhotoTask.getMaxPhotoCount());
                }
                case BarcodeTask oldBarcodeTask when newTask instanceof BarcodeTask newBarcodeTask -> {
                    newBarcodeTask.setMinBarcodeCount(oldBarcodeTask.getMinBarcodeCount());
                    newBarcodeTask.setMaxBarcodeCount(oldBarcodeTask.getMaxBarcodeCount());
                }
                case CommentTask oldCommentTask when newTask instanceof CommentTask newCommentTask -> {
                    newCommentTask.setCommentText(oldCommentTask.getCommentText());
                    newCommentTask.setRequired(oldCommentTask.isRequired());
                }
                default -> {
                }
                }

                // Replace in state and preserve order
                int index = tasksState.indexOf(oldTask);
                if (index >= 0) {
                    newTask.setTaskOrder(index);
                    tasksState.set(index, newTask);
                    currentTask[0] = newTask;
                }

                updateTaskConfiguration(configContainer, newTask);
                triggerValidation();
                updateTabLabels();
            }
        });

        // Render the UI with the loaded task directly (which IS in tasksState)
        updateTaskConfiguration(configContainer, task);
        triggerValidation();
        updateTabLabels();

        tasksList.add(taskContainer);
    }

    /**
     * Gets the TaskType enum value from a BaseTask instance
     */
    private TaskType getTaskTypeFromTask(BaseTask task) {
        if (task instanceof ConfirmationTask)
            return TaskType.CONFIRMATION;
        if (task instanceof SignatureTask)
            return TaskType.SIGNATURE;
        if (task instanceof TodoListTask)
            return TaskType.TODOLIST;
        if (task instanceof PhotoTask)
            return TaskType.PHOTO;
        if (task instanceof BarcodeTask)
            return TaskType.BARCODE;
        if (task instanceof CommentTask)
            return TaskType.COMMENT;
        return TaskType.CONFIRMATION; // fallback
    }

    // ============================================
    // Adressvalidierung
    // ============================================

    /**
     * Wird aufgerufen, wenn der Benutzer den Tab wechselt. Prüft, ob vom Tab
     * "Auftraggeber & Adressen" gewechselt wird und ob die Adressen geändert
     * wurden.
     */
    private void onTabChange(com.vaadin.flow.component.tabs.TabSheet.SelectedChangeEvent event) {
        com.vaadin.flow.component.tabs.Tab previousTab = event.getPreviousTab();
        com.vaadin.flow.component.tabs.Tab selectedTab = event.getSelectedTab();

        // Nur prüfen, wenn vom Adress-Tab weg gewechselt wird
        if (previousTab != addressesTab) {
            return;
        }

        log.debug("Tab-Wechsel von Adress-Tab zu '{}' - addressesDirty={}", selectedTab.getLabel(), addressesDirty);

        // Wenn der Validierungsdialog gerade geöffnet ist, nichts tun
        if (validationDialogOpen) {
            log.debug("Validierungsdialog ist geöffnet - ignoriere Tab-Wechsel");
            return;
        }

        // Prüfen, ob Adressen geändert wurden
        boolean pickupChanged = hasPickupAddressChanged();
        boolean deliveryChanged = hasDeliveryAddressChanged();

        log.debug("Adressänderung: pickupChanged={}, deliveryChanged={}", pickupChanged, deliveryChanged);

        if (!pickupChanged && !deliveryChanged) {
            // Adressen nicht geändert, nichts zu tun
            log.debug("Keine Adressänderung - Dialog wird nicht angezeigt");
            return;
        }

        // Tab-Wechsel vorübergehend verhindern
        // Flag setzen, Dialog anzeigen, und Tab zurücksetzen
        validationDialogOpen = true;
        tabSheet.setSelectedTab(addressesTab);

        // Validierungsdialog anzeigen
        log.debug("Zeige Validierungsdialog an");
        showAddressValidationDialog(selectedTab);
    }

    /**
     * Prüft, ob die Abholadresse gültig ist (Pflichtfelder ausgefüllt).
     */
    private boolean hasPickupAddressChanged() {
        String currentStreet = getValueOrEmpty(pickupStreet);
        String currentZip = getValueOrEmpty(pickupZip);
        String currentCity = getValueOrEmpty(pickupCity);

        // Nur true zurückgeben, wenn alle Pflichtfelder ausgefüllt sind und Validierung
        // nötig ist
        return addressesDirty && !currentStreet.isEmpty() && !currentZip.isEmpty() && !currentCity.isEmpty();
    }

    /**
     * Prüft, ob die Lieferadresse gültig ist (Pflichtfelder ausgefüllt).
     */
    private boolean hasDeliveryAddressChanged() {
        String currentStreet = getValueOrEmpty(deliveryStreet);
        String currentZip = getValueOrEmpty(deliveryZip);
        String currentCity = getValueOrEmpty(deliveryCity);

        // Nur true zurückgeben, wenn alle Pflichtfelder ausgefüllt sind und Validierung
        // nötig ist
        return addressesDirty && !currentStreet.isEmpty() && !currentZip.isEmpty() && !currentCity.isEmpty();
    }

    private String getValueOrEmpty(TextField field) {
        return field.getValue() != null ? field.getValue().trim() : "";
    }

    /**
     * Zeigt den Adressvalidierungsdialog an. Die Prüfung erfolgt im Hintergrund und
     * der Dialog wird aktualisiert, sobald die Ergebnisse vorliegen.
     */
    private void showAddressValidationDialog(com.vaadin.flow.component.tabs.Tab targetTab) {
        final Dialog dialog = new Dialog();
        dialog.setHeaderTitle("Adressen werden überprüft");
        dialog.setWidth("500px");
        dialog.setModal(true);
        dialog.setCloseOnOutsideClick(false);
        dialog.setCloseOnEsc(false);

        final VerticalLayout content = new VerticalLayout();
        content.setPadding(true);
        content.setSpacing(true);

        // Initiale Meldung mit Progress
        final Span loadingMessage = new Span("Adressen werden bei Google Maps überprüft...");
        loadingMessage.getStyle().set("font-style", "italic");
        loadingMessage.getStyle().set("color", "var(--lumo-secondary-text-color)");

        // Progress-Indikator
        final com.vaadin.flow.component.progressbar.ProgressBar progressBar = new com.vaadin.flow.component.progressbar.ProgressBar();
        progressBar.setIndeterminate(true);
        progressBar.setWidthFull();

        content.add(loadingMessage, progressBar);

        // Layout für die Ergebnisanzeige (initial versteckt)
        final VerticalLayout resultLayout = new VerticalLayout();
        resultLayout.setVisible(false);
        resultLayout.setPadding(false);
        resultLayout.setSpacing(true);

        final Span pickupResultLabel = new Span();
        final Span deliveryResultLabel = new Span();

        // Route-Label für die Anzeige der berechneten Strecke
        final Span routeResultLabel = new Span();
        routeResultLabel.getStyle().set("font-weight", "bold");
        routeResultLabel.getStyle().set("margin-top", "var(--lumo-space-s)");
        routeResultLabel.setVisible(false);

        resultLayout.add(pickupResultLabel, deliveryResultLabel, routeResultLabel);
        content.add(resultLayout);

        // Button-Layout (initial versteckt)
        final HorizontalLayout buttonLayout = new HorizontalLayout();
        buttonLayout.setWidthFull();
        buttonLayout.setJustifyContentMode(FlexComponent.JustifyContentMode.END);
        buttonLayout.setVisible(false);

        final Button cancelButton = new Button("Zurück", e -> {
            dialog.close();
            // Im Adress-Tab bleiben
            validationDialogOpen = false;
            log.debug("Dialog geschlossen (Zurück), validationDialogOpen=false");
        });
        cancelButton.addThemeVariants(ButtonVariant.LUMO_TERTIARY);

        final Button continueButton = new Button("Trotzdem wechseln", e -> {
            dialog.close();
            // Zum Ziel-Tab wechseln
            tabSheet.setSelectedTab(targetTab);
            // Adressen als validiert markieren
            markAddressesAsValidated();
            validationDialogOpen = false;
            log.debug("Dialog geschlossen (Weiter), validationDialogOpen=false");
        });
        continueButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);

        buttonLayout.add(cancelButton, continueButton);
        content.add(buttonLayout);

        dialog.add(content);
        dialog.open();

        // Adressdaten speichern für die Validierung
        final String pickupStreetValue = getValueOrEmpty(pickupStreet);
        final String pickupHouseNumberValue = getValueOrEmpty(pickupHouseNumber);
        final String pickupZipValue = getValueOrEmpty(pickupZip);
        final String pickupCityValue = getValueOrEmpty(pickupCity);
        final boolean pickupChanged = hasPickupAddressChanged();

        final String deliveryStreetValue = getValueOrEmpty(deliveryStreet);
        final String deliveryHouseNumberValue = getValueOrEmpty(deliveryHouseNumber);
        final String deliveryZipValue = getValueOrEmpty(deliveryZip);
        final String deliveryCityValue = getValueOrEmpty(deliveryCity);
        final boolean deliveryChanged = hasDeliveryAddressChanged();

        // Asynchrone Validierung im Hintergrund durchführen
        getUI().ifPresent(ui -> {
            // CompletableFuture für Hintergrund-Verarbeitung
            java.util.concurrent.CompletableFuture.runAsync(() -> {
                // Abholadresse validieren
                final AddressValidationResult[] pickupResultHolder = new AddressValidationResult[1];
                if (pickupChanged) {
                    pickupResultHolder[0] = addressValidationService.validateAddress("pickup", pickupStreetValue,
                            pickupHouseNumberValue, pickupZipValue, pickupCityValue);
                }

                // Lieferadresse validieren
                final AddressValidationResult[] deliveryResultHolder = new AddressValidationResult[1];
                if (deliveryChanged) {
                    deliveryResultHolder[0] = addressValidationService.validateAddress("delivery", deliveryStreetValue,
                            deliveryHouseNumberValue, deliveryZipValue, deliveryCityValue);
                }

                // UI aktualisieren mit den Ergebnissen
                ui.access(() -> {
                    // Ergebnisse speichern
                    if (pickupResultHolder[0] != null) {
                        addressValidationResults.put("pickup", pickupResultHolder[0]);
                    }
                    if (deliveryResultHolder[0] != null) {
                        addressValidationResults.put("delivery", deliveryResultHolder[0]);
                    }

                    // Ergebnisse ermitteln
                    AddressValidationResult pickupResult = pickupResultHolder[0] != null ? pickupResultHolder[0]
                            : addressValidationResults.get("pickup");
                    AddressValidationResult deliveryResult = deliveryResultHolder[0] != null ? deliveryResultHolder[0]
                            : addressValidationResults.get("delivery");

                    // Lade-Anzeige ausblenden
                    loadingMessage.setVisible(false);
                    progressBar.setVisible(false);

                    // Prüfen ob beide Adressen gültig sind
                    boolean bothValid = (pickupResult != null && pickupResult.isValid())
                            && (deliveryResult != null && deliveryResult.isValid());

                    // Route berechnen wenn beide gültig
                    if (bothValid) {
                        routeCalculationResult = addressValidationService.calculateRoute(pickupResult, deliveryResult);
                    }

                    // Ergebnisse anzeigen
                    updateValidationDialogResults(pickupResult, deliveryResult, pickupResultLabel, deliveryResultLabel,
                            routeResultLabel, resultLayout, buttonLayout, continueButton, targetTab);
                });
            });
        });
    }

    /**
     * Aktualisiert die Ergebnisanzeige im Validierungsdialog.
     */
    private void updateValidationDialogResults(AddressValidationResult pickupResult,
            AddressValidationResult deliveryResult, Span pickupResultLabel, Span deliveryResultLabel,
            Span routeResultLabel, VerticalLayout resultLayout, HorizontalLayout buttonLayout, Button continueButton,
            com.vaadin.flow.component.tabs.Tab targetTab) {

        boolean hasInvalidAddress = false;
        boolean bothAddressesValid = true;

        // Abholadresse anzeigen
        if (pickupResult != null) {
            if (pickupResult.isValid()) {
                pickupResultLabel.setText("✓ Abholadresse: " + pickupResult.getFormattedAddress());
                pickupResultLabel.getStyle().set("color", "var(--lumo-success-text-color)");
            } else {
                pickupResultLabel.setText("⚠ Abholadresse: " + pickupResult.getValidationMessage());
                pickupResultLabel.getStyle().set("color", "var(--lumo-error-text-color)");
                hasInvalidAddress = true;
                bothAddressesValid = false;
            }
        } else {
            pickupResultLabel.setVisible(false);
        }

        // Lieferadresse anzeigen
        if (deliveryResult != null) {
            if (deliveryResult.isValid()) {
                deliveryResultLabel.setText("✓ Lieferadresse: " + deliveryResult.getFormattedAddress());
                deliveryResultLabel.getStyle().set("color", "var(--lumo-success-text-color)");
            } else {
                deliveryResultLabel.setText("⚠ Lieferadresse: " + deliveryResult.getValidationMessage());
                deliveryResultLabel.getStyle().set("color", "var(--lumo-error-text-color)");
                hasInvalidAddress = true;
                bothAddressesValid = false;
            }
        } else {
            deliveryResultLabel.setVisible(false);
        }

        // Route anzeigen, wenn beide Adressen gültig sind
        if (bothAddressesValid && routeCalculationResult != null && routeCalculationResult.isValid()) {
            routeResultLabel.setText("🚛 Route: " + String.format("%.1f km", routeCalculationResult.getDistanceKm())
                    + " (Fahrtzeit: " + routeCalculationResult.getFormattedDurationLong() + ")");
            routeResultLabel.getStyle().set("color", "var(--lumo-primary-text-color)");
            routeResultLabel.setVisible(true);
        } else {
            routeResultLabel.setVisible(false);
        }

        // Ergebnisse anzeigen
        resultLayout.setVisible(true);

        // Farbliche Markierung der Adressfelder
        updateAddressFieldStyles(pickupResult, deliveryResult);

        // Buttons anzeigen
        buttonLayout.setVisible(true);

        // Wenn beide Adressen gültig sind, direkt weiter
        if (!hasInvalidAddress) {
            continueButton.setText("Weiter");
        } else {
            continueButton.setText("Trotzdem wechseln");
        }

        // Route-Info im Preis-Tab aktualisieren
        updateRouteInfoBox();
    }

    /**
     * Aktualisiert die Route-Info-Box im Preis-Tab mit den aktuellen Routendaten.
     * Zeigt entweder die berechnete Route oder die manuelle Eingabe an.
     */
    private void updateRouteInfoBox() {
        if (routeInfoBox == null || manualRouteInputBox == null) {
            return;
        }

        if (routeCalculationResult != null && routeCalculationResult.isValid()) {
            // Berechnete Route anzeigen
            routeDistanceLabel.setText(String.format("%.1f km", routeCalculationResult.getDistanceKm()));
            routeDurationLabel.setText(routeCalculationResult.getFormattedDurationLong());
            routeInfoBox.setVisible(true);
            manualRouteInputBox.setVisible(false);

            // Update price summary and grid with new route distance
            updatePriceSummary();
            if (servicesGrid != null) {
                servicesGrid.getDataProvider().refreshAll();
            }
        } else {
            // Manuelle Eingabe anzeigen
            routeInfoBox.setVisible(false);
            manualRouteInputBox.setVisible(true);
        }
    }

    /**
     * Aktualisiert die Hintergrundfarbe der Adressfelder basierend auf dem
     * Validierungsergebnis. Hellgrün für validierte Adressen, hellgelb für nicht
     * validierte.
     */
    private void updateAddressFieldStyles(AddressValidationResult pickupResult,
            AddressValidationResult deliveryResult) {
        // Abholadresse - hellgrün (#90EE90) für validiert, hellgelb (#FFFACD) für nicht
        // validiert
        String pickupColor = (pickupResult != null && pickupResult.isValid()) ? "rgba(144, 238, 144, 0.5)" // Hellgrün
                                                                                                           // mit
                                                                                                           // Transparenz
                : "rgba(255, 250, 205, 0.5)"; // Hellgelb mit Transparenz

        pickupStreet.getStyle().set("--vaadin-input-field-background", pickupColor);
        pickupHouseNumber.getStyle().set("--vaadin-input-field-background", pickupColor);
        pickupZip.getStyle().set("--vaadin-input-field-background", pickupColor);
        pickupCity.getStyle().set("--vaadin-input-field-background", pickupColor);

        // Lieferadresse - hellgrün für validiert, hellgelb für nicht validiert
        String deliveryColor = (deliveryResult != null && deliveryResult.isValid()) ? "rgba(144, 238, 144, 0.5)" // Hellgrün
                                                                                                                 // mit
                                                                                                                 // Transparenz
                : "rgba(255, 250, 205, 0.5)"; // Hellgelb mit Transparenz

        deliveryStreet.getStyle().set("--vaadin-input-field-background", deliveryColor);
        deliveryHouseNumber.getStyle().set("--vaadin-input-field-background", deliveryColor);
        deliveryZip.getStyle().set("--vaadin-input-field-background", deliveryColor);
        deliveryCity.getStyle().set("--vaadin-input-field-background", deliveryColor);
    }

    /**
     * Markiert die Adressen als validiert (nach erfolgreicher Prüfung).
     */
    private void markAddressesAsValidated() {
        addressesDirty = false;
        log.debug("Adressen als validiert markiert");
    }

    /**
     * Gibt das Validierungsergebnis für die Abholadresse zurück. Kann null sein,
     * wenn noch keine Validierung durchgeführt wurde.
     */
    public AddressValidationResult getPickupAddressValidationResult() {
        return addressValidationResults.get("pickup");
    }

    /**
     * Gibt das Validierungsergebnis für die Lieferadresse zurück. Kann null sein,
     * wenn noch keine Validierung durchgeführt wurde.
     */
    public AddressValidationResult getDeliveryAddressValidationResult() {
        return addressValidationResults.get("delivery");
    }

    /**
     * Gibt alle Validierungsergebnisse zurück.
     */
    public Map<String, AddressValidationResult> getAddressValidationResults() {
        return new HashMap<>(addressValidationResults);
    }

    /**
     * Gibt das Ergebnis der Routenberechnung zurück. Enthält die Entfernung in
     * Kilometern und die Fahrtzeit, wenn beide Adressen validiert wurden.
     *
     * @return RouteCalculationResult oder null, wenn keine Berechnung durchgeführt
     *         wurde
     */
    public RouteCalculationResult getRouteCalculationResult() {
        return routeCalculationResult;
    }

    /**
     * Gibt die berechnete oder manuell eingegebene Entfernung zurück (für Preisberechnungen).
     *
     * @return Entfernung in km oder 0.0, wenn keine Berechnung oder Eingabe vorhanden ist
     */
    public double getRouteDistanceKm() {
        if (routeCalculationResult != null && routeCalculationResult.isValid()) {
            return routeCalculationResult.getDistanceKm();
        }
        // Manuelle Eingabe verwenden, wenn vorhanden
        if (manualDistanceInput != null && manualDistanceInput.getValue() != null) {
            return manualDistanceInput.getValue();
        }
        return 0.0;
    }

    /**
     * Gibt die effektive Routendistanz zurück (berechnet oder manuell eingegeben).
     * 
     * @return Distanz als Double oder null, wenn keine Distanz verfügbar
     */
    private Double getEffectiveRouteDistance() {
        if (routeCalculationResult != null && routeCalculationResult.isValid()) {
            return routeCalculationResult.getDistanceKm();
        }
        if (manualDistanceInput != null && manualDistanceInput.getValue() != null) {
            return manualDistanceInput.getValue();
        }
        return null;
    }

    /**
     * Gibt die effektive Fahrtzeit zurück (berechnet oder manuell eingegeben).
     * 
     * @return Dauer in Sekunden oder null, wenn keine Dauer verfügbar
     */
    private Integer getEffectiveRouteDuration() {
        if (routeCalculationResult != null && routeCalculationResult.isValid()) {
            return routeCalculationResult.getDurationSeconds();
        }
        if (manualDurationInput != null && manualDurationInput.getValue() != null) {
            return manualDurationInput.getValue() * 60; // Minuten in Sekunden
        }
        return null;
    }

    /**
     * Registriert ValueChangeListener für alle Adressfelder, um bei Änderungen die
     * Streckeninformationen zurückzusetzen.
     */
    private void setupAddressChangeListeners() {
        // Abholadress-Felder
        pickupCompany.addValueChangeListener(e -> {
            if (e.isFromClient()) {
                resetRouteInformation();
            }
        });
        pickupStreet.addValueChangeListener(e -> {
            if (e.isFromClient()) {
                resetRouteInformation();
            }
        });
        pickupHouseNumber.addValueChangeListener(e -> {
            if (e.isFromClient()) {
                resetRouteInformation();
            }
        });
        pickupZip.addValueChangeListener(e -> {
            if (e.isFromClient()) {
                resetRouteInformation();
            }
        });
        pickupCity.addValueChangeListener(e -> {
            if (e.isFromClient()) {
                resetRouteInformation();
            }
        });

        // Lieferadress-Felder
        deliveryCompany.addValueChangeListener(e -> {
            if (e.isFromClient()) {
                resetRouteInformation();
            }
        });
        deliveryStreet.addValueChangeListener(e -> {
            if (e.isFromClient()) {
                resetRouteInformation();
            }
        });
        deliveryHouseNumber.addValueChangeListener(e -> {
            if (e.isFromClient()) {
                resetRouteInformation();
            }
        });
        deliveryZip.addValueChangeListener(e -> {
            if (e.isFromClient()) {
                resetRouteInformation();
            }
        });
        deliveryCity.addValueChangeListener(e -> {
            if (e.isFromClient()) {
                resetRouteInformation();
            }
        });
    }

    /**
     * Setzt alle Streckeninformationen zurück, wenn sich Adressdaten ändern. Dies
     * bewirkt, dass der Validierungsdialog beim Tab-Wechsel erneut angezeigt wird.
     */
    private void resetRouteInformation() {
        // Flag setzen, dass Adressen geändert wurden
        addressesDirty = true;

        // Routenberechnung zurücksetzen
        routeCalculationResult = null;

        // Validierungsergebnisse zurücksetzen
        addressValidationResults.clear();

        // Route-Info-Box im Preis-Tab verstecken und manuelle Eingabe anzeigen
        if (routeInfoBox != null) {
            routeInfoBox.setVisible(false);
        }
        if (manualRouteInputBox != null) {
            manualRouteInputBox.setVisible(true);
        }

        log.debug("Streckeninformationen zurückgesetzt aufgrund von Adressänderungen");
    }

}
