package de.assecutor.votianlt.pages.base.ui.component;

import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.checkbox.Checkbox;
import com.vaadin.flow.component.combobox.ComboBox;
import com.vaadin.flow.component.datepicker.DatePicker;
import com.vaadin.flow.component.dialog.Dialog;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.component.html.H3;
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.orderedlayout.FlexComponent;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.tabs.Tab;
import com.vaadin.flow.component.tabs.TabSheet;
import com.vaadin.flow.component.textfield.IntegerField;
import com.vaadin.flow.component.textfield.NumberField;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.component.timepicker.TimePicker;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.progressbar.ProgressBar;
import de.assecutor.votianlt.model.AddressValidationResult;
import de.assecutor.votianlt.model.AppUser;
import de.assecutor.votianlt.model.CargoItem;
import de.assecutor.votianlt.model.Customer;
import de.assecutor.votianlt.pages.service.AddressValidationService;

import java.time.LocalDate;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

/**
 * Dialog for editing pickup station data. Contains address form fields,
 * customer selection, appointments & processing tab, and cargo tab.
 */
public class PickupStationDialog extends Dialog {

    /**
     * Data holder for pickup station fields.
     */
    public static class PickupData {
        private String company;
        private String salutation;
        private String firstName;
        private String lastName;
        private String phone;
        private String mail;
        private String street;
        private String houseNumber;
        private String addressAddition;
        private String zip;
        private String city;
        private boolean saveAddress;
        private String customerSelection;
        private LocalDate appointmentDate;
        private LocalTime appointmentTime;
        private boolean digitalProcessing;
        private AppUser appUser;
        private List<CargoItem> cargoItems = new ArrayList<>();
        private boolean addressValidatedByGoogle;
        private AddressValidationResult addressValidationResult;

        public boolean isAddressValidatedByGoogle() {
            return addressValidatedByGoogle;
        }

        public void setAddressValidatedByGoogle(boolean addressValidatedByGoogle) {
            this.addressValidatedByGoogle = addressValidatedByGoogle;
        }

        public AddressValidationResult getAddressValidationResult() {
            return addressValidationResult;
        }

        public void setAddressValidationResult(AddressValidationResult addressValidationResult) {
            this.addressValidationResult = addressValidationResult;
        }

        public String getCompany() {
            return company;
        }

        public void setCompany(String company) {
            this.company = company;
        }

        public String getSalutation() {
            return salutation;
        }

        public void setSalutation(String salutation) {
            this.salutation = salutation;
        }

        public String getFirstName() {
            return firstName;
        }

        public void setFirstName(String firstName) {
            this.firstName = firstName;
        }

        public String getLastName() {
            return lastName;
        }

        public void setLastName(String lastName) {
            this.lastName = lastName;
        }

        public String getPhone() {
            return phone;
        }

        public void setPhone(String phone) {
            this.phone = phone;
        }

        public String getMail() {
            return mail;
        }

        public void setMail(String mail) {
            this.mail = mail;
        }

        public String getStreet() {
            return street;
        }

        public void setStreet(String street) {
            this.street = street;
        }

        public String getHouseNumber() {
            return houseNumber;
        }

        public void setHouseNumber(String houseNumber) {
            this.houseNumber = houseNumber;
        }

        public String getAddressAddition() {
            return addressAddition;
        }

        public void setAddressAddition(String addressAddition) {
            this.addressAddition = addressAddition;
        }

        public String getZip() {
            return zip;
        }

        public void setZip(String zip) {
            this.zip = zip;
        }

        public String getCity() {
            return city;
        }

        public void setCity(String city) {
            this.city = city;
        }

        public boolean isSaveAddress() {
            return saveAddress;
        }

        public void setSaveAddress(boolean saveAddress) {
            this.saveAddress = saveAddress;
        }

        public String getCustomerSelection() {
            return customerSelection;
        }

        public void setCustomerSelection(String customerSelection) {
            this.customerSelection = customerSelection;
        }

        public LocalDate getAppointmentDate() {
            return appointmentDate;
        }

        public void setAppointmentDate(LocalDate appointmentDate) {
            this.appointmentDate = appointmentDate;
        }

        public LocalTime getAppointmentTime() {
            return appointmentTime;
        }

        public void setAppointmentTime(LocalTime appointmentTime) {
            this.appointmentTime = appointmentTime;
        }

        public boolean isDigitalProcessing() {
            return digitalProcessing;
        }

        public void setDigitalProcessing(boolean digitalProcessing) {
            this.digitalProcessing = digitalProcessing;
        }

        public AppUser getAppUser() {
            return appUser;
        }

        public void setAppUser(AppUser appUser) {
            this.appUser = appUser;
        }

        public List<CargoItem> getCargoItems() {
            return cargoItems;
        }

        public void setCargoItems(List<CargoItem> cargoItems) {
            this.cargoItems = cargoItems != null ? cargoItems : new ArrayList<>();
        }

        private org.bson.types.ObjectId customerId;
        private boolean addressDiffersFromCustomer;

        public org.bson.types.ObjectId getCustomerId() {
            return customerId;
        }

        public void setCustomerId(org.bson.types.ObjectId customerId) {
            this.customerId = customerId;
        }

        public boolean isAddressDiffersFromCustomer() {
            return addressDiffersFromCustomer;
        }

        public void setAddressDiffersFromCustomer(boolean addressDiffersFromCustomer) {
            this.addressDiffersFromCustomer = addressDiffersFromCustomer;
        }
    }

    public interface SaveListener {
        void onSave(PickupData data);
    }

    private final ComboBox<String> company;
    private final ComboBox<String> salutation;
    private final TextField firstName;
    private final TextField lastName;
    private final TextField phone;
    private final TextField mail;
    private final TextField street;
    private final TextField houseNumber;
    private final TextField addressAddition;
    private final TextField zip;
    private final TextField city;
    private final Checkbox saveAddress;

    private final ComboBox<String> customerComboBox;
    private final Map<String, Customer> customerLabelMap = new LinkedHashMap<>();
    private final Map<String, Customer> companyCustomerMap = new LinkedHashMap<>();
    private org.bson.types.ObjectId selectedCustomerId;
    private DatePicker appointmentDatePicker;
    private TimePicker appointmentTimePicker;
    private Checkbox digitalProcessingCheckbox;
    private ComboBox<AppUser> appUserComboBox;
    private final List<CargoItem> cargoItemsState = new ArrayList<>();
    private VerticalLayout cargoList;

    private Span addressTabError;
    private Span appointmentsTabError;
    private Span cargoTabError;

    private final DeliveryStationTile.TranslationHelper translationHelper;

    public PickupStationDialog(String dialogTitle, List<Customer> customers,
            DeliveryStationTile.TranslationHelper translationHelper, SaveListener saveListener,
            List<AppUser> availableAppUsers, AddressValidationService addressValidationService) {

        this.translationHelper = translationHelper;

        setHeaderTitle(dialogTitle);
        setCloseOnOutsideClick(false);
        setWidth("960px");
        setHeight("80vh");

        // Remove white rounded card from dialog overlay
        getElement().setAttribute("theme", "no-inner-card");

        // Address form
        VerticalLayout formLayout = new VerticalLayout();
        formLayout.setPadding(true);
        formLayout.setSpacing(true);
        formLayout.setWidthFull();

        // Principal selection
        customerComboBox = new ComboBox<>(translationHelper.getTranslation("addjob.customer.label"));
        customerComboBox.setPlaceholder(translationHelper.getTranslation("addjob.customer.placeholder"));
        customerComboBox.setRequiredIndicatorVisible(true);
        customerComboBox.setWidthFull();

        customerLabelMap.clear();
        for (Customer c : customers) {
            CustomerAddressLabelHelper.putName(customerLabelMap, c,
                    translationHelper.getTranslation("addjob.customer.unnamed"));
        }
        customerComboBox.setItems(new ArrayList<>(customerLabelMap.keySet()));

        // Pickup address with autocomplete
        company = new ComboBox<>(translationHelper.getTranslation("addjob.address.pickup.label"));
        company.setPlaceholder(translationHelper.getTranslation("addjob.address.pickup.placeholder"));
        company.setAllowCustomValue(true);
        company.setWidthFull();
        setupCompanyAutocomplete(company, customers);

        // Salutation
        salutation = new ComboBox<>(translationHelper.getTranslation("addjob.address.salutation"));
        salutation.setItems(translationHelper.getTranslation("addjob.salutation.mr"),
                translationHelper.getTranslation("addjob.salutation.ms"),
                translationHelper.getTranslation("addjob.salutation.other"));
        salutation.setPlaceholder(translationHelper.getTranslation("addjob.address.salutation.placeholder"));
        salutation.setWidthFull();

        // First name
        firstName = new TextField(translationHelper.getTranslation("profile.firstname"));
        firstName.setPlaceholder(translationHelper.getTranslation("profile.firstname"));
        firstName.setRequiredIndicatorVisible(true);
        firstName.setWidthFull();

        // Last name
        lastName = new TextField(translationHelper.getTranslation("profile.lastname"));
        lastName.setPlaceholder(translationHelper.getTranslation("profile.lastname"));
        lastName.setRequiredIndicatorVisible(true);
        lastName.setWidthFull();

        // Phone
        phone = new TextField(translationHelper.getTranslation("profile.phone"));
        phone.setPlaceholder(translationHelper.getTranslation("profile.phone"));
        phone.setWidthFull();

        // E-Mail
        mail = new TextField(translationHelper.getTranslation("customers.column.email"));
        mail.setPlaceholder(translationHelper.getTranslation("customers.column.email"));
        mail.setWidthFull();

        // Street + house number
        street = new TextField(translationHelper.getTranslation("profile.street"));
        street.setPlaceholder(translationHelper.getTranslation("profile.street"));
        street.setRequiredIndicatorVisible(true);

        houseNumber = new TextField(translationHelper.getTranslation("profile.housenr"));
        houseNumber.setPlaceholder(translationHelper.getTranslation("addjob.address.housenumber"));
        houseNumber.setRequiredIndicatorVisible(true);

        HorizontalLayout streetLayout = new HorizontalLayout();
        streetLayout.setWidthFull();
        streetLayout.setSpacing(true);
        street.setWidth("70%");
        houseNumber.setWidth("30%");
        streetLayout.add(street, houseNumber);

        // Address addition
        addressAddition = new TextField(translationHelper.getTranslation("profile.addressadd"));
        addressAddition
                .setPlaceholder(translationHelper.getTranslation("addjob.address.delivery.addition.placeholder"));
        addressAddition.setWidthFull();

        // Zip + city
        zip = new TextField(translationHelper.getTranslation("profile.zip"));
        zip.setPlaceholder(translationHelper.getTranslation("profile.zip"));
        zip.setRequiredIndicatorVisible(true);

        city = new TextField(translationHelper.getTranslation("addjob.address.city"));
        city.setPlaceholder(translationHelper.getTranslation("addjob.address.city"));
        city.setRequiredIndicatorVisible(true);

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

        // Save address checkbox
        saveAddress = new Checkbox(translationHelper.getTranslation("addjob.address.save"));
        saveAddress.setValue(true);
        saveAddress.setWidthFull();

        // Clear error styling on value change for required fields and update tab
        // indicators
        firstName.addValueChangeListener(ev -> {
            validateRequiredFields();
            updateSaveAddressState();
        });
        lastName.addValueChangeListener(ev -> {
            validateRequiredFields();
            updateSaveAddressState();
        });
        street.addValueChangeListener(ev -> {
            validateRequiredFields();
            updateSaveAddressState();
        });
        houseNumber.addValueChangeListener(ev -> {
            validateRequiredFields();
            updateSaveAddressState();
        });
        zip.addValueChangeListener(ev -> {
            validateRequiredFields();
            updateSaveAddressState();
        });
        city.addValueChangeListener(ev -> {
            validateRequiredFields();
            updateSaveAddressState();
        });
        salutation.addValueChangeListener(ev -> updateSaveAddressState());
        phone.addValueChangeListener(ev -> updateSaveAddressState());
        addressAddition.addValueChangeListener(ev -> updateSaveAddressState());
        mail.addValueChangeListener(ev -> {
            validateRequiredFields();
            updateSaveAddressState();
        });
        saveAddress.addValueChangeListener(ev -> {
            updateMailRequirement();
            validateRequiredFields();
        });

        // Customer selection fills address fields
        customerComboBox.addValueChangeListener(ev -> {
            String selected = ev.getValue();
            if (selected == null) {
                selectedCustomerId = null;
                updateSaveAddressState();
                return;
            }
            Customer c = customerLabelMap.get(selected);
            if (c == null) {
                selectedCustomerId = null;
                updateSaveAddressState();
                return;
            }
            selectedCustomerId = c.getId();
            setCompanySelection(c);
            if (c.getTitle() != null && ("Herr".equalsIgnoreCase(c.getTitle()) || "Frau".equalsIgnoreCase(c.getTitle())
                    || "Divers".equalsIgnoreCase(c.getTitle())))
                salutation.setValue(c.getTitle());
            else
                salutation.clear();
            if (c.getFirstname() != null)
                firstName.setValue(c.getFirstname());
            else
                firstName.clear();
            if (c.getLastName() != null)
                lastName.setValue(c.getLastName());
            else
                lastName.clear();
            if (c.getTelephone() != null)
                phone.setValue(c.getTelephone());
            else
                phone.clear();
            if (c.getMail() != null)
                mail.setValue(c.getMail());
            else
                mail.clear();
            if (c.getStreet() != null)
                street.setValue(c.getStreet());
            else
                street.clear();
            if (c.getHouseNumber() != null)
                houseNumber.setValue(c.getHouseNumber());
            else
                houseNumber.clear();
            if (c.getAddressAddition() != null)
                addressAddition.setValue(c.getAddressAddition());
            else
                addressAddition.clear();
            if (c.getZip() != null)
                zip.setValue(c.getZip());
            else
                zip.clear();
            if (c.getCity() != null)
                city.setValue(c.getCity());
            else
                city.clear();

            updateSaveAddressState();
        });

        Div addressDivider = new Div();
        addressDivider.setWidthFull();
        addressDivider.getStyle().set("border-top", "1px solid var(--lumo-contrast-20pct)");
        addressDivider.getStyle().set("margin", "var(--lumo-space-m) 0 var(--lumo-space-s)");

        formLayout.add(customerComboBox, addressDivider, company, salutation, firstName, lastName, phone, mail, streetLayout,
                addressAddition, zipCityLayout, saveAddress);

        // TabSheet with address, appointments, and cargo tabs
        TabSheet tabSheet = new TabSheet();
        tabSheet.setWidthFull();
        tabSheet.setSizeFull();

        addressTabError = createTabErrorIndicator();
        appointmentsTabError = createTabErrorIndicator();
        cargoTabError = createTabErrorIndicator();

        Tab addressTab = tabSheet.add(translationHelper.getTranslation("addjob.tab.pickup.address"), formLayout);
        addressTab.add(addressTabError);
        Tab appointmentsTab = tabSheet.add(translationHelper.getTranslation("addjob.tab.appointments"),
                createAppointmentsTab(availableAppUsers));
        appointmentsTab.add(appointmentsTabError);
        Tab cargoTab = tabSheet.add(translationHelper.getTranslation("addjob.tab.cargo"), createCargoTab());
        cargoTab.add(cargoTabError);

        // Red border frame filling the dialog
        Div redFrame = new Div();
        redFrame.getStyle().set("border", "10px solid transparent");
        redFrame.getStyle().set("border-radius", "0");
        redFrame.getStyle().set("box-sizing", "border-box");
        redFrame.getStyle().set("display", "flex");
        redFrame.getStyle().set("flex-direction", "column");
        redFrame.getStyle().set("flex", "1");
        redFrame.setSizeFull();

        // White card with rounded corners inside the red frame
        Div whiteCard = new Div();
        whiteCard.getStyle().set("background", "white");
        whiteCard.getStyle().set("border-radius", "24px");
        whiteCard.getStyle().set("flex", "1");
        whiteCard.getStyle().set("overflow", "auto");
        whiteCard.setSizeFull();
        whiteCard.add(tabSheet);

        redFrame.add(whiteCard);
        add(redFrame);

        // Footer buttons
        Button saveButton = new Button(translationHelper.getTranslation("dialog.confirm"), e -> {
            if (!validateRequiredFields()) {
                Notification.show(translationHelper.getTranslation("addjob.validation.required.fields"), 3000,
                        Notification.Position.BOTTOM_END);
                return;
            }

            // Warte-Dialog anzeigen
            Dialog loadingDialog = DialogStylingHelper
                    .createStyledDialog(translationHelper.getTranslation("addjob.validation.dialog.title"), "420px");
            loadingDialog.setCloseOnOutsideClick(false);
            loadingDialog.setCloseOnEsc(false);
            VerticalLayout loadingContent = DialogStylingHelper.createContentLayout("320px",
                    FlexComponent.Alignment.CENTER);
            loadingContent.setAlignItems(FlexComponent.Alignment.CENTER);
            loadingContent.getStyle().set("text-align", "center");
            Span loadingText = new Span(translationHelper.getTranslation("addjob.validation.dialog.loading"));
            ProgressBar progressBar = new ProgressBar();
            progressBar.setIndeterminate(true);
            progressBar.setWidthFull();
            loadingContent.add(loadingText, progressBar);
            loadingDialog.add(DialogStylingHelper.wrapContent(loadingContent));
            loadingDialog.open();

            // Adresse asynchron bei Google validieren
            UI ui = UI.getCurrent();
            String streetVal = street.getValue();
            String houseNumberVal = houseNumber.getValue();
            String zipVal = zip.getValue();
            String cityVal = city.getValue();

            CompletableFuture.supplyAsync(() -> addressValidationService.validateAddress("pickup", streetVal,
                    houseNumberVal, zipVal, cityVal)).thenAccept(validationResult -> ui.access(() -> {
                        loadingDialog.close();
                        PickupData data = collectData();

                        if (validationResult.isValid()) {
                            data.setAddressValidatedByGoogle(true);
                            data.setAddressValidationResult(validationResult);
                            if (saveListener != null) {
                                saveListener.onSave(data);
                            }
                            close();
                        } else {
                            // Adresse nicht gefunden: Benutzer fragen
                            Dialog confirmDialog = DialogStylingHelper.createConfirmationDialog(
                                    translationHelper.getTranslation("addjob.validation.address.not.found.title"),
                                    translationHelper.getTranslation("addjob.validation.address.not.found.message"),
                                    "560px",
                                    translationHelper.getTranslation("addjob.validation.address.correct"),
                                    translationHelper.getTranslation("addjob.validation.address.save.anyway"),
                                    () -> {
                                        data.setAddressValidatedByGoogle(false);
                                        data.setAddressValidationResult(validationResult);
                                        if (saveListener != null) {
                                            saveListener.onSave(data);
                                        }
                                        close();
                                    },
                                    ButtonVariant.LUMO_PRIMARY);
                            confirmDialog.open();
                        }
                    }));
        });
        saveButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);

        Button cancelButton = new Button(translationHelper.getTranslation("dialog.cancel"), e -> close());

        getFooter().add(cancelButton, saveButton);

        addOpenedChangeListener(event -> {
            if (event.isOpened()) {
                validateRequiredFields();
            }
        });
    }

    /**
     * Pre-fills the dialog fields with existing data.
     */
    public void setData(PickupData data) {
        if (data == null)
            return;
        String customerSelection = normalizeValue(data.getCustomerSelection());
        if (!customerSelection.isEmpty()) {
            if (!customerLabelMap.containsKey(customerSelection)) {
                customerLabelMap.put(customerSelection, null);
                customerComboBox.setItems(new ArrayList<>(customerLabelMap.keySet()));
            }
            customerComboBox.setValue(customerSelection);
        } else {
            customerComboBox.clear();
        }
        String companyOption = findCompanyOptionLabel(data);
        boolean customerSelectedFromOptions = companyOption != null;
        if (companyOption != null) {
            company.setValue(companyOption);
        } else if (data.getCompany() != null) {
            company.setValue(data.getCompany());
        }
        if (data.getSalutation() != null)
            salutation.setValue(data.getSalutation());
        if (data.getFirstName() != null)
            firstName.setValue(data.getFirstName());
        if (data.getLastName() != null)
            lastName.setValue(data.getLastName());
        if (data.getPhone() != null)
            phone.setValue(data.getPhone());
        if (data.getMail() != null)
            mail.setValue(data.getMail());
        else
            mail.clear();
        if (data.getStreet() != null)
            street.setValue(data.getStreet());
        if (data.getHouseNumber() != null)
            houseNumber.setValue(data.getHouseNumber());
        if (data.getAddressAddition() != null)
            addressAddition.setValue(data.getAddressAddition());
        if (data.getZip() != null)
            zip.setValue(data.getZip());
        if (data.getCity() != null)
            city.setValue(data.getCity());
        if (data.getAppointmentDate() != null && appointmentDatePicker != null) {
            appointmentDatePicker.setValue(data.getAppointmentDate());
        }
        if (data.getAppointmentTime() != null && appointmentTimePicker != null) {
            appointmentTimePicker.setValue(data.getAppointmentTime());
        }
        if (digitalProcessingCheckbox != null) {
            digitalProcessingCheckbox.setValue(data.isDigitalProcessing());
        }
        if (data.getAppUser() != null && appUserComboBox != null) {
            appUserComboBox.setValue(data.getAppUser());
        }
        if (data.getCargoItems() != null && !data.getCargoItems().isEmpty() && cargoList != null) {
            cargoItemsState.clear();
            cargoList.removeAll();
            for (CargoItem item : data.getCargoItems()) {
                addCargoRowWithData(item);
            }
        }

        if (data.getCustomerId() != null) {
            selectedCustomerId = data.getCustomerId();
        } else {
            Customer matched = companyOption != null ? companyCustomerMap.get(companyOption) : null;
            selectedCustomerId = matched != null ? matched.getId() : null;
        }
        saveAddress.setValue(customerSelectedFromOptions ? false : data.isSaveAddress());
        updateSaveAddressState();
    }

    private PickupData collectData() {
        PickupData data = new PickupData();
        data.setCompany(resolveCompanyValue(company.getValue()));
        data.setSalutation(salutation.getValue());
        data.setFirstName(firstName.getValue());
        data.setLastName(lastName.getValue());
        data.setPhone(phone.getValue());
        data.setMail(mail.getValue());
        data.setStreet(street.getValue());
        data.setHouseNumber(houseNumber.getValue());
        data.setAddressAddition(addressAddition.getValue());
        data.setZip(zip.getValue());
        data.setCity(city.getValue());
        data.setSaveAddress(saveAddress.getValue());
        data.setCustomerId(selectedCustomerId);
        data.setAddressDiffersFromCustomer(computeAddressDiffers());
        data.setCustomerSelection(customerComboBox.getValue());
        if (appointmentDatePicker != null) {
            data.setAppointmentDate(appointmentDatePicker.getValue());
        }
        if (appointmentTimePicker != null) {
            data.setAppointmentTime(appointmentTimePicker.getValue());
        }
        if (digitalProcessingCheckbox != null) {
            data.setDigitalProcessing(digitalProcessingCheckbox.getValue());
        }
        if (appUserComboBox != null) {
            data.setAppUser(appUserComboBox.getValue());
        }
        data.setCargoItems(new ArrayList<>(cargoItemsState));
        return data;
    }

    private boolean validateRequiredFields() {
        // Address tab validation
        boolean addressValid = true;
        addressValid &= validateTextField(firstName);
        addressValid &= validateTextField(lastName);
        addressValid &= validateTextField(street);
        addressValid &= validateTextField(houseNumber);
        addressValid &= validateTextField(zip);
        addressValid &= validateTextField(city);
        addressValid &= validateMailField();
        if (addressTabError != null) {
            addressTabError.setVisible(!addressValid);
        }

        // Appointments tab validation
        boolean appointmentsValid = true;
        if (appointmentDatePicker != null) {
            boolean dateEmpty = appointmentDatePicker.getValue() == null;
            applyErrorStyling(appointmentDatePicker, dateEmpty);
            appointmentsValid &= !dateEmpty;
        }
        if (digitalProcessingCheckbox != null && Boolean.TRUE.equals(digitalProcessingCheckbox.getValue())
                && appUserComboBox != null) {
            boolean appUserEmpty = appUserComboBox.getValue() == null;
            applyErrorStyling(appUserComboBox, appUserEmpty);
            appointmentsValid &= !appUserEmpty;
        }
        if (appointmentsTabError != null) {
            appointmentsTabError.setVisible(!appointmentsValid);
        }

        // Cargo tab validation
        boolean cargoValid = validateCargoItems();
        if (cargoTabError != null) {
            cargoTabError.setVisible(!cargoValid);
        }

        return addressValid && appointmentsValid && cargoValid;
    }

    private boolean validateTextField(TextField field) {
        boolean empty = field.getValue() == null || field.getValue().trim().isEmpty();
        applyErrorStyling(field, empty);
        return !empty;
    }

    private boolean validateMailField() {
        String value = mail.getValue();
        String normalizedValue = value == null ? "" : value.trim();
        boolean invalid = !normalizedValue.isEmpty() && !normalizedValue.contains("@");
        applyErrorStyling(mail, invalid);
        return !invalid;
    }

    private boolean validateCargoItems() {
        boolean valid = true;
        if (cargoList == null)
            return true;
        for (com.vaadin.flow.component.Component rowComp : cargoList.getChildren().toList()) {
            if (rowComp instanceof HorizontalLayout row) {
                for (com.vaadin.flow.component.Component field : row.getChildren().toList()) {
                    if (field instanceof ComboBox<?> combo && combo.isRequiredIndicatorVisible()) {
                        boolean empty = combo.getValue() == null || combo.getValue().toString().trim().isEmpty();
                        applyErrorStyling(combo, empty);
                        if (empty)
                            valid = false;
                    } else if (field instanceof IntegerField intField && intField.isRequiredIndicatorVisible()) {
                        boolean empty = intField.getValue() == null;
                        applyErrorStyling(intField, empty);
                        if (empty)
                            valid = false;
                    } else if (field instanceof NumberField numField && numField.isRequiredIndicatorVisible()) {
                        boolean empty = numField.getValue() == null;
                        applyErrorStyling(numField, empty);
                        if (empty)
                            valid = false;
                    }
                }
            }
        }
        return valid;
    }

    private void applyErrorStyling(com.vaadin.flow.component.Component field, boolean error) {
        if (error) {
            field.getElement().getStyle().set("--vaadin-input-field-background", "rgba(255, 0, 0, 0.1)");
            field.getElement().getStyle().set("--vaadin-input-field-border-color", "rgba(255, 0, 0, 0.3)");
        } else {
            field.getElement().getStyle().remove("--vaadin-input-field-background");
            field.getElement().getStyle().remove("--vaadin-input-field-border-color");
        }
    }

    private Span createTabErrorIndicator() {
        Span indicator = new Span(" !");
        indicator.getStyle().set("color", "var(--lumo-error-color)");
        indicator.getStyle().set("font-weight", "bold");
        indicator.getStyle().set("margin-left", "4px");
        indicator.setVisible(false);
        return indicator;
    }

    private void setupCompanyAutocomplete(ComboBox<String> companyField, List<Customer> customers) {
        companyCustomerMap.clear();
        for (Customer customer : customers) {
            CustomerAddressLabelHelper.put(companyCustomerMap, customer,
                    translationHelper.getTranslation("addjob.customer.unnamed"));
        }
        companyField.setItems(new ArrayList<>(companyCustomerMap.keySet()));

        companyField.addValueChangeListener(event -> {
            String selectedAddress = event.getValue();
            if (selectedAddress == null || selectedAddress.trim().isEmpty()) {
                selectedCustomerId = null;
                updateSaveAddressState();
                return;
            }

            Customer customer = companyCustomerMap.get(selectedAddress);
            if (customer != null) {
                applyCustomerAddress(customer);
            }

            updateSaveAddressState();
        });

        companyField.addCustomValueSetListener(event -> {
            companyField.setValue(event.getDetail());
            selectedCustomerId = null;
            updateSaveAddressState();
        });
    }

    private void updateSaveAddressState() {
        Customer selectedCustomer = customerLabelMap.get(customerComboBox.getValue());
        Customer selectedCompanyCustomer = companyCustomerMap.get(company.getValue());
        boolean customerDataMatches = selectedCustomer != null && matchesCustomer(selectedCustomer);
        boolean companyDataMatches = selectedCompanyCustomer != null && matchesCustomer(selectedCompanyCustomer);

        if (customerDataMatches || companyDataMatches) {
            saveAddress.setValue(false);
            saveAddress.setEnabled(false);
            saveAddress.setLabel(translationHelper.getTranslation("addjob.address.save"));
            updateMailRequirement();
            return;
        }

        saveAddress.setEnabled(true);
        if (selectedCustomerId != null) {
            saveAddress.setLabel(translationHelper.getTranslation("addjob.address.update"));
        } else {
            saveAddress.setLabel(translationHelper.getTranslation("addjob.address.save"));
        }
        updateMailRequirement();
    }

    private void updateMailRequirement() {
        mail.setRequiredIndicatorVisible(false);
    }

    private boolean matchesCustomer(Customer customer) {
        return sameValue(resolveCompanyValue(company.getValue()), customer.getCompanyName())
                && sameValue(salutation.getValue(), customer.getTitle())
                && sameValue(firstName.getValue(), customer.getFirstname())
                && sameValue(lastName.getValue(), customer.getLastName())
                && sameValue(phone.getValue(), customer.getTelephone())
                && sameValue(mail.getValue(), customer.getMail())
                && sameValue(street.getValue(), customer.getStreet())
                && sameValue(houseNumber.getValue(), customer.getHouseNumber())
                && sameValue(addressAddition.getValue(), customer.getAddressAddition())
                && sameValue(zip.getValue(), customer.getZip())
                && sameValue(city.getValue(), customer.getCity());
    }

    private boolean sameValue(String left, String right) {
        return normalizeValue(left).equals(normalizeValue(right));
    }

    private String normalizeValue(String value) {
        return value == null ? "" : value.trim();
    }

    private boolean computeAddressDiffers() {
        boolean hasAnyValue = !normalizeValue(resolveCompanyValue(company.getValue())).isEmpty()
                || !normalizeValue(firstName.getValue()).isEmpty() || !normalizeValue(lastName.getValue()).isEmpty()
                || !normalizeValue(phone.getValue()).isEmpty() || !normalizeValue(mail.getValue()).isEmpty()
                || !normalizeValue(street.getValue()).isEmpty() || !normalizeValue(houseNumber.getValue()).isEmpty()
                || !normalizeValue(addressAddition.getValue()).isEmpty() || !normalizeValue(zip.getValue()).isEmpty()
                || !normalizeValue(city.getValue()).isEmpty();
        if (!hasAnyValue) {
            return false;
        }
        if (selectedCustomerId == null) {
            return true;
        }
        Customer linked = findCustomerById(selectedCustomerId);
        return linked == null || !matchesCustomer(linked);
    }

    private Customer findCustomerById(org.bson.types.ObjectId id) {
        if (id == null) {
            return null;
        }
        for (Customer c : customerLabelMap.values()) {
            if (c != null && id.equals(c.getId())) {
                return c;
            }
        }
        for (Customer c : companyCustomerMap.values()) {
            if (c != null && id.equals(c.getId())) {
                return c;
            }
        }
        return null;
    }

    private void applyCustomerAddress(Customer customer) {
        selectedCustomerId = customer.getId();
        if (customer.getTitle() != null
                && ("Herr".equalsIgnoreCase(customer.getTitle()) || "Frau".equalsIgnoreCase(customer.getTitle())
                        || "Divers".equalsIgnoreCase(customer.getTitle()))) {
            salutation.setValue(customer.getTitle());
        } else {
            salutation.clear();
        }
        if (customer.getFirstname() != null)
            firstName.setValue(customer.getFirstname());
        else
            firstName.clear();
        if (customer.getLastName() != null)
            lastName.setValue(customer.getLastName());
        else
            lastName.clear();
        if (customer.getTelephone() != null)
            phone.setValue(customer.getTelephone());
        else
            phone.clear();
        if (customer.getMail() != null)
            mail.setValue(customer.getMail());
        else
            mail.clear();
        if (customer.getStreet() != null)
            street.setValue(customer.getStreet());
        else
            street.clear();
        if (customer.getHouseNumber() != null)
            houseNumber.setValue(customer.getHouseNumber());
        else
            houseNumber.clear();
        if (customer.getAddressAddition() != null)
            addressAddition.setValue(customer.getAddressAddition());
        else
            addressAddition.clear();
        if (customer.getZip() != null)
            zip.setValue(customer.getZip());
        else
            zip.clear();
        if (customer.getCity() != null)
            city.setValue(customer.getCity());
        else
            city.clear();
    }

    private void setCompanySelection(Customer customer) {
        String label = findCompanyOptionLabel(customer);
        if (label != null) {
            company.setValue(label);
        } else if (customer.getCompanyName() != null && !customer.getCompanyName().isBlank()) {
            company.setValue(customer.getCompanyName());
        } else {
            company.clear();
        }
    }

    private String resolveCompanyValue(String comboValue) {
        return CustomerAddressLabelHelper.resolveCompanyValue(companyCustomerMap, comboValue);
    }

    private String findCompanyOptionLabel(Customer customer) {
        if (customer == null || customer.getId() == null) {
            return null;
        }
        for (Map.Entry<String, Customer> entry : companyCustomerMap.entrySet()) {
            Customer option = entry.getValue();
            if (option != null && customer.getId().equals(option.getId())) {
                return entry.getKey();
            }
        }
        return null;
    }

    private String findCompanyOptionLabel(PickupData data) {
        for (Map.Entry<String, Customer> entry : companyCustomerMap.entrySet()) {
            Customer customer = entry.getValue();
            if (data.getCustomerId() != null && customer.getId() != null && data.getCustomerId().equals(customer.getId())) {
                return entry.getKey();
            }
            if (matchesCustomer(customer, data)) {
                return entry.getKey();
            }
        }
        return null;
    }

    private boolean matchesCustomer(Customer customer, PickupData data) {
        return sameValue(customer.getCompanyName(), data.getCompany())
                && sameValue(customer.getTitle(), data.getSalutation())
                && sameValue(customer.getFirstname(), data.getFirstName())
                && sameValue(customer.getLastName(), data.getLastName())
                && sameValue(customer.getTelephone(), data.getPhone())
                && sameValue(customer.getMail(), data.getMail())
                && sameValue(customer.getStreet(), data.getStreet())
                && sameValue(customer.getHouseNumber(), data.getHouseNumber())
                && sameValue(customer.getAddressAddition(), data.getAddressAddition())
                && sameValue(customer.getZip(), data.getZip())
                && sameValue(customer.getCity(), data.getCity());
    }

    // ============================================
    // Appointments & Processing Tab
    // ============================================

    private VerticalLayout createAppointmentsTab(List<AppUser> availableAppUsers) {
        VerticalLayout tabContent = new VerticalLayout();
        tabContent.setSizeFull();
        tabContent.setPadding(true);
        tabContent.setSpacing(true);
        tabContent.setDefaultHorizontalComponentAlignment(FlexComponent.Alignment.CENTER);

        VerticalLayout content = new VerticalLayout();
        content.setPadding(false);
        content.setSpacing(true);
        content.setWidth("720px");
        content.setDefaultHorizontalComponentAlignment(FlexComponent.Alignment.STRETCH);

        // Digital processing + App user
        digitalProcessingCheckbox = new Checkbox(translationHelper.getTranslation("profile.settings.digitalprocess"));
        digitalProcessingCheckbox.setValue(true);

        HorizontalLayout digitalRow = new HorizontalLayout();
        digitalRow.setWidthFull();
        digitalRow.setAlignItems(FlexComponent.Alignment.BASELINE);
        digitalRow.setJustifyContentMode(FlexComponent.JustifyContentMode.START);
        digitalProcessingCheckbox.getStyle().set("margin-right", "12px");
        digitalRow.add(digitalProcessingCheckbox);

        appUserComboBox = new ComboBox<>(translationHelper.getTranslation("addjob.appuser.label"));
        appUserComboBox.setWidthFull();
        if (availableAppUsers != null) {
            appUserComboBox.setItems(availableAppUsers);
        }
        appUserComboBox.setItemLabelGenerator(
                user -> user.getVorname() + " " + user.getNachname() + " (" + user.getEmail() + ")");
        appUserComboBox.setPlaceholder(translationHelper.getTranslation("addjob.appuser.placeholder"));
        appUserComboBox.addValueChangeListener(ev -> validateRequiredFields());

        content.add(digitalRow, appUserComboBox);

        // Toggle app user visibility based on digital processing
        digitalProcessingCheckbox.addValueChangeListener(e -> {
            boolean required = Boolean.TRUE.equals(e.getValue());
            appUserComboBox.setRequiredIndicatorVisible(required);
            appUserComboBox.setVisible(required);
            if (!required) {
                appUserComboBox.clear();
            }
            validateRequiredFields();
        });
        boolean digitalInitial = Boolean.TRUE.equals(digitalProcessingCheckbox.getValue());
        appUserComboBox.setRequiredIndicatorVisible(digitalInitial);
        appUserComboBox.setVisible(digitalInitial);

        // Appointment date & time
        H3 pickupApptTitle = new H3(translationHelper.getTranslation("addjob.appointment.pickup"));
        pickupApptTitle.getStyle().set("margin", "0");

        appointmentDatePicker = new DatePicker(translationHelper.getTranslation("addjob.appointment.date"));
        appointmentDatePicker.setRequiredIndicatorVisible(true);
        appointmentDatePicker.setMin(LocalDate.now());
        appointmentDatePicker.setLocale(java.util.Locale.GERMANY);
        appointmentDatePicker.setI18n(new DatePicker.DatePickerI18n().setFirstDayOfWeek(1)
                .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")));

        appointmentTimePicker = new TimePicker(translationHelper.getTranslation("addjob.appointment.time"));
        appointmentTimePicker.setLocale(java.util.Locale.GERMANY);

        appointmentDatePicker.addValueChangeListener(ev -> validateRequiredFields());

        HorizontalLayout pickupApptRow = new HorizontalLayout(appointmentDatePicker, appointmentTimePicker);
        pickupApptRow.setWidthFull();
        pickupApptRow.setSpacing(true);
        appointmentDatePicker.setWidth("50%");
        appointmentTimePicker.setWidth("50%");
        content.add(pickupApptTitle, pickupApptRow);

        // Info about delivery dates
        Span deliveryInfoLabel = new Span(translationHelper.getTranslation("addjob.appointment.delivery.info"));
        deliveryInfoLabel.addClassName("inline-caption");
        deliveryInfoLabel.getStyle().set("margin-top", "var(--lumo-space-m)");
        content.add(deliveryInfoLabel);

        tabContent.add(content);
        return tabContent;
    }

    // ============================================
    // Cargo Tab
    // ============================================

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

        VerticalLayout wrapper = new VerticalLayout();
        wrapper.setWidthFull();
        wrapper.setSpacing(true);

        VerticalLayout cargoAreaContainer = new VerticalLayout();
        cargoAreaContainer.setWidthFull();
        cargoAreaContainer.setSpacing(true);

        H3 cargoTitle = new H3(translationHelper.getTranslation("addjob.tab.cargo"));

        wrapper.add(cargoTitle);

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

        // Add one empty row by default
        addCargoRow();

        // Add button
        Button addCargoButton = new Button(translationHelper.getTranslation("addjob.cargo.add"),
                new Icon(VaadinIcon.PLUS));
        addCargoButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        addCargoButton.setWidthFull();
        addCargoButton.addClickListener(e -> addCargoRow());

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

    private void addCargoRow() {
        addCargoRowWithData(null);
    }

    private void addCargoRowWithData(CargoItem existingItem) {
        HorizontalLayout row = new HorizontalLayout();
        row.setWidthFull();
        row.setAlignItems(FlexComponent.Alignment.END);

        ComboBox<String> desc = new ComboBox<>(translationHelper.getTranslation("addjob.cargo.description"));
        desc.setItems(translationHelper.getTranslation("addjob.cargo.europalette"),
                translationHelper.getTranslation("addjob.cargo.disposablepalette"),
                translationHelper.getTranslation("addjob.cargo.dusseldorfpalette"),
                translationHelper.getTranslation("addjob.cargo.gridboxpalette"),
                translationHelper.getTranslation("addjob.cargo.gridcart"),
                translationHelper.getTranslation("addjob.cargo.parcel"));
        desc.setAllowCustomValue(true);
        desc.addCustomValueSetListener(event -> desc.setValue(event.getDetail()));
        desc.setPlaceholder(translationHelper.getTranslation("addjob.cargo.description.placeholder"));
        desc.setWidth("40%");
        desc.setRequiredIndicatorVisible(true);

        IntegerField qty = new IntegerField(translationHelper.getTranslation("addjob.cargo.quantity"));
        qty.setMin(1);
        qty.setMax(9999);
        qty.setWidth("10%");
        qty.setRequiredIndicatorVisible(true);

        NumberField weight = new NumberField(translationHelper.getTranslation("addjob.cargo.weight"));
        weight.setSuffixComponent(new Span("kg"));
        weight.setWidth("15%");
        weight.setRequiredIndicatorVisible(true);

        NumberField len = new NumberField(translationHelper.getTranslation("addjob.cargo.length"));
        len.setSuffixComponent(new Span("cm"));
        len.setWidth("12%");
        len.setRequiredIndicatorVisible(true);

        NumberField wid = new NumberField(translationHelper.getTranslation("addjob.cargo.width"));
        wid.setSuffixComponent(new Span("cm"));
        wid.setWidth("12%");
        wid.setRequiredIndicatorVisible(true);

        NumberField hei = new NumberField(translationHelper.getTranslation("addjob.cargo.height"));
        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);
        });

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

        // Create or use existing CargoItem
        CargoItem item = new CargoItem();
        if (existingItem != null) {
            item.setDescription(existingItem.getDescription());
            item.setQuantity(existingItem.getQuantity());
            item.setWeightKg(existingItem.getWeightKg());
            item.setLengthMm(existingItem.getLengthMm());
            item.setWidthMm(existingItem.getWidthMm());
            item.setHeightMm(existingItem.getHeightMm());

            // Pre-fill fields
            if (item.getDescription() != null)
                desc.setValue(item.getDescription());
            if (item.getQuantity() != null)
                qty.setValue(item.getQuantity());
            if (item.getWeightKg() != null)
                weight.setValue(item.getWeightKg());
            if (item.getLengthMm() != null)
                len.setValue(item.getLengthMm());
            if (item.getWidthMm() != null)
                wid.setValue(item.getWidthMm());
            if (item.getHeightMm() != null)
                hei.setValue(item.getHeightMm());
        }
        cargoItemsState.add(item);

        // Bind change listeners
        desc.addValueChangeListener(ev -> {
            item.setDescription(ev.getValue());
            applyErrorStyling(desc, ev.getValue() == null || ev.getValue().trim().isEmpty());
            validateRequiredFields();
        });
        qty.addValueChangeListener(ev -> {
            item.setQuantity(ev.getValue());
            applyErrorStyling(qty, ev.getValue() == null);
            validateRequiredFields();
        });
        weight.addValueChangeListener(ev -> {
            item.setWeightKg(ev.getValue());
            applyErrorStyling(weight, ev.getValue() == null);
            validateRequiredFields();
        });
        len.addValueChangeListener(ev -> {
            item.setLengthMm(ev.getValue());
            applyErrorStyling(len, ev.getValue() == null);
            validateRequiredFields();
        });
        wid.addValueChangeListener(ev -> {
            item.setWidthMm(ev.getValue());
            applyErrorStyling(wid, ev.getValue() == null);
            validateRequiredFields();
        });
        hei.addValueChangeListener(ev -> {
            item.setHeightMm(ev.getValue());
            applyErrorStyling(hei, ev.getValue() == null);
            validateRequiredFields();
        });
    }
}
