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.dialog.Dialog;
import com.vaadin.flow.component.dnd.DragSource;
import com.vaadin.flow.component.dnd.DropEffect;
import com.vaadin.flow.component.dnd.DropTarget;
import com.vaadin.flow.component.dnd.EffectAllowed;
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.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.tabs.Tab;
import com.vaadin.flow.component.tabs.TabSheet;
import com.vaadin.flow.component.textfield.IntegerField;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.progressbar.ProgressBar;
import de.assecutor.votianlt.model.AddressValidationResult;
import de.assecutor.votianlt.model.Customer;
import de.assecutor.votianlt.model.TaskTemplate;
import de.assecutor.votianlt.model.task.*;
import de.assecutor.votianlt.pages.service.AddressValidationService;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;

/**
 * Dialog for editing delivery station data. Contains address form fields and a
 * tasks tab for task management with templates.
 */
public class DeliveryStationDialog extends Dialog {

    /**
     * Data holder for delivery station fields.
     */
    public static class DeliveryData {
        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 boolean addressDiffersFromCustomer;
        private org.bson.types.ObjectId customerId;

        public boolean isAddressDiffersFromCustomer() {
            return addressDiffersFromCustomer;
        }

        public void setAddressDiffersFromCustomer(boolean addressDiffersFromCustomer) {
            this.addressDiffersFromCustomer = addressDiffersFromCustomer;
        }
        private List<BaseTask> tasks = new ArrayList<>();
        private boolean addressValidatedByGoogle;
        private AddressValidationResult addressValidationResult;

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

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

        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 List<BaseTask> getTasks() {
            return tasks;
        }

        public void setTasks(List<BaseTask> tasks) {
            this.tasks = tasks != null ? tasks : new ArrayList<>();
        }
    }

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

    /**
     * Callback interface for saving task templates.
     */
    public interface TemplateSaveCallback {
        void saveTemplate(String templateName, List<BaseTask> tasks);
    }

    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 List<BaseTask> tasksState = new ArrayList<>();
    private VerticalLayout tasksList;
    private VerticalLayout draggedTaskContainer;

    private Span addressTabError;
    private Span tasksTabError;

    private final DeliveryStationTile.TranslationHelper translationHelper;
    private final java.util.Map<String, Customer> companyAddressOptions = new java.util.LinkedHashMap<>();
    private org.bson.types.ObjectId selectedCustomerId;

    public DeliveryStationDialog(String dialogTitle, List<Customer> customers,
            DeliveryStationTile.TranslationHelper translationHelper, SaveListener saveListener,
            List<TaskTemplate> templates, TemplateSaveCallback templateSaveCallback,
            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();

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

        // 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();
        formLayout.add(salutation);

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

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

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

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

        // 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);
        formLayout.add(streetLayout);

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

        // 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);
        formLayout.add(zipCityLayout);

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

        // 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();
        });

        // TabSheet with address and tasks tabs
        TabSheet tabSheet = new TabSheet();
        tabSheet.setWidthFull();
        tabSheet.setSizeFull();

        addressTabError = createTabErrorIndicator();
        tasksTabError = createTabErrorIndicator();

        Tab addressTab = tabSheet.add(translationHelper.getTranslation("addjob.tab.delivery.address"), formLayout);
        addressTab.add(addressTabError);
        Tab tasksTab = tabSheet.add(translationHelper.getTranslation("addjob.tab.tasks"),
                createTasksTab(templates, templateSaveCallback));
        tasksTab.add(tasksTabError);

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

        // White card with rounded corners inside the 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);

        frame.add(whiteCard);
        add(frame);

        // 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("delivery", streetVal,
                    houseNumberVal, zipVal, cityVal)).thenAccept(validationResult -> ui.access(() -> {
                        loadingDialog.close();
                        DeliveryData 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(DeliveryData data) {
        if (data == null)
            return;
        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());
        selectedCustomerId = data.getCustomerId();
        if (selectedCustomerId == null && customerSelectedFromOptions) {
            Customer matched = companyAddressOptions.get(companyOption);
            if (matched != null) {
                selectedCustomerId = matched.getId();
            }
        }
        saveAddress.setValue(customerSelectedFromOptions ? false : data.isSaveAddress());
        updateSaveAddressState();

        // Load tasks into dialog state
        if (data.getTasks() != null && !data.getTasks().isEmpty()) {
            tasksState.clear();
            if (tasksList != null) {
                tasksList.removeAll();
            }
            for (BaseTask task : data.getTasks()) {
                BaseTask copy = createTaskCopy(task);
                if (copy != null) {
                    tasksState.add(copy);
                    if (tasksList != null) {
                        createTaskRowFromTask(copy);
                    }
                }
            }
        }

    }

    private DeliveryData collectData() {
        DeliveryData data = new DeliveryData();
        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.setTasks(new ArrayList<>(tasksState));
        return data;
    }

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

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

    private boolean isBlank(String value) {
        return value == null || value.trim().isEmpty();
    }

    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();
        addressTabError.setVisible(!addressValid);

        // Tasks tab validation
        boolean tasksValid = validateTasks();
        tasksTabError.setVisible(!tasksValid);

        return addressValid && tasksValid;
    }

    private boolean validateTasks() {
        boolean valid = true;
        for (BaseTask task : tasksState) {
            if (task instanceof ConfirmationTask ct) {
                if (ct.getDescription() == null || ct.getDescription().trim().isEmpty()) {
                    valid = false;
                }
                if (ct.getButtonText() == null || ct.getButtonText().trim().isEmpty()) {
                    valid = false;
                }
            } else if (task instanceof TodoListTask tt) {
                if (tt.getTodoItems() == null || tt.getTodoItems().isEmpty()
                        || tt.getTodoItems().stream().allMatch(item -> item == null || item.trim().isEmpty())) {
                    valid = false;
                }
            }
        }
        return valid;
    }

    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 empty = normalizedValue.isEmpty();
        boolean invalid = !empty && !normalizedValue.contains("@");
        applyErrorStyling(mail, invalid);
        return !invalid;
    }

    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) {
        companyAddressOptions.clear();
        for (Customer customer : customers) {
            CustomerAddressLabelHelper.put(companyAddressOptions, customer,
                    translationHelper.getTranslation("addjob.customer.unnamed"));
        }

        companyField.setItems(new ArrayList<>(companyAddressOptions.keySet()));

        companyField.addValueChangeListener(event -> {
            Customer customer = companyAddressOptions.get(event.getValue());
            if (customer == null) {
                selectedCustomerId = null;
                updateSaveAddressState();
                return;
            }

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

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

    private void updateSaveAddressState() {
        Customer selectedCustomer = companyAddressOptions.get(company.getValue());
        boolean customerDataMatches = selectedCustomer != null && matchesCurrentCustomer(selectedCustomer);

        if (customerDataMatches) {
            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 String resolveCompanyValue(String comboValue) {
        return CustomerAddressLabelHelper.resolveCompanyValue(companyAddressOptions, comboValue);
    }

    private String findCompanyOptionLabel(DeliveryData data) {
        for (java.util.Map.Entry<String, Customer> entry : companyAddressOptions.entrySet()) {
            Customer customer = entry.getValue();
            if (matchesCustomer(customer, data)) {
                return entry.getKey();
            }
        }
        return null;
    }

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

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

    private boolean equalsNormalized(String left, String right) {
        String normalizedLeft = left != null ? left.trim() : "";
        String normalizedRight = right != null ? right.trim() : "";
        return normalizedLeft.equalsIgnoreCase(normalizedRight);
    }

    // ============================================
    // Task Management
    // ============================================

    private VerticalLayout createTasksTab(List<TaskTemplate> templates, TemplateSaveCallback templateSaveCallback) {
        VerticalLayout tabContent = new VerticalLayout();
        tabContent.setSizeFull();
        tabContent.setPadding(true);
        tabContent.setSpacing(true);

        VerticalLayout wrapper = new VerticalLayout();
        wrapper.setWidthFull();
        wrapper.setDefaultHorizontalComponentAlignment(FlexComponent.Alignment.CENTER);

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

        // Task title with template selection
        H3 tasksTitle = new H3(translationHelper.getTranslation("addjob.tasks.title"));
        tasksTitle.getStyle().set("margin", "0");
        tasksTitle.getStyle().set("white-space", "nowrap");

        ComboBox<TaskTemplate> templateComboBox = new ComboBox<>();
        templateComboBox.setPlaceholder(translationHelper.getTranslation("addjob.tasks.template.placeholder"));
        templateComboBox.setItemLabelGenerator(TaskTemplate::getTemplateName);
        templateComboBox.setClearButtonVisible(true);
        templateComboBox.setWidthFull();

        if (templates != null) {
            templateComboBox.setItems(templates);
        }

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

        // Icon button to save as template
        Button saveAsTemplateBtn = new Button(new Icon(VaadinIcon.BOOKMARK));
        saveAsTemplateBtn.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
        saveAsTemplateBtn.setTooltipText(translationHelper.getTranslation("addjob.tasks.template.save.tooltip"));
        saveAsTemplateBtn.addClickListener(e -> saveTasksAsTemplate(templateSaveCallback, templateComboBox));

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

        // Dynamic task list
        tasksList = new VerticalLayout();
        tasksList.setPadding(false);
        tasksList.setSpacing(true);

        // Add 1 example row, then append a signature task once on initial setup
        createTaskRow();
        ensureTrailingSignatureTask();

        Button addTaskBtn = new Button(translationHelper.getTranslation("addjob.tasks.add"), new Icon(VaadinIcon.PLUS));
        addTaskBtn.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        addTaskBtn.addClickListener(e -> createTaskRow());

        content.add(tasksList, addTaskBtn);
        wrapper.add(content);
        tabContent.add(wrapper);
        return tabContent;
    }

    private void createTaskRow() {
        VerticalLayout taskContainer = new VerticalLayout();
        taskContainer.setPadding(true);
        taskContainer.setSpacing(true);
        taskContainer.addClassName("dialog-task-card");

        // Drag handle
        Button dragHandle = new Button(new Icon(VaadinIcon.GRID_SMALL));
        dragHandle.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
        dragHandle.addClassName("dialog-task-drag-handle");

        // Compact summary shown during drag
        HorizontalLayout summaryRow = createDragSummary("", "");
        summaryRow.addClassName("dialog-task-summary");

        // Task type selection
        ComboBox<TaskType> taskTypeCombo = new ComboBox<>(translationHelper.getTranslation("addjob.tasks.tasktype"));
        taskTypeCombo.setItems(TaskType.values());
        taskTypeCombo.setItemLabelGenerator(TaskType::getDisplayName);
        taskTypeCombo.setPlaceholder(translationHelper.getTranslation("addjob.tasks.tasktype.placeholder"));
        taskTypeCombo.setWidthFull();

        // Configuration container for dynamic fields
        VerticalLayout configContainer = new VerticalLayout();
        configContainer.setPadding(false);
        configContainer.setSpacing(true);
        configContainer.addClassName("dialog-task-config");

        // 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.addClassName("dialog-floating-delete");
        deleteXButton.addClickListener(e -> removeTaskRow(taskContainer));

        HorizontalLayout headerRow = new HorizontalLayout(dragHandle, summaryRow, taskTypeCombo, deleteXButton);
        headerRow.setAlignItems(FlexComponent.Alignment.START);
        headerRow.setWidthFull();
        headerRow.setFlexGrow(1, taskTypeCombo);

        taskContainer.add(headerRow, configContainer);

        setupDragAndDrop(taskContainer);

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

        final BaseTask[] currentTask = { task };

        taskTypeCombo.setValue(TaskType.CONFIRMATION);
        updateTaskConfiguration(configContainer, currentTask[0]);
        updateDragSummary(summaryRow, TaskType.CONFIRMATION, task);

        taskTypeCombo.addValueChangeListener(ev -> {
            TaskType selectedType = ev.getValue();
            if (selectedType != null) {
                BaseTask newTask = createTaskByType(selectedType);
                BaseTask oldTask = currentTask[0];

                newTask.setDescription(oldTask.getDescription());
                newTask.setOptional(oldTask.isOptional());
                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);
                updateDragSummary(summaryRow, selectedType, newTask);
            }
        });

        tasksList.add(taskContainer);
        updateTaskDeleteAvailability();
    }

    private void createTaskRowFromTask(BaseTask task) {
        VerticalLayout taskContainer = new VerticalLayout();
        taskContainer.setPadding(true);
        taskContainer.setSpacing(true);
        taskContainer.addClassName("dialog-task-card");

        // Drag handle
        Button dragHandle = new Button(new Icon(VaadinIcon.GRID_SMALL));
        dragHandle.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
        dragHandle.addClassName("dialog-task-drag-handle");

        // Compact summary shown during drag
        TaskType initialTaskType = getTaskTypeFromTask(task);
        HorizontalLayout summaryRow = createDragSummary(
                initialTaskType != null ? initialTaskType.getDisplayName() : "",
                task.getDescription() != null ? task.getDescription() : "");
        summaryRow.addClassName("dialog-task-summary");

        ComboBox<TaskType> taskTypeCombo = new ComboBox<>(translationHelper.getTranslation("addjob.tasks.tasktype"));
        taskTypeCombo.setItems(TaskType.values());
        taskTypeCombo.setItemLabelGenerator(TaskType::getDisplayName);
        taskTypeCombo.setPlaceholder(translationHelper.getTranslation("addjob.tasks.tasktype.placeholder"));
        taskTypeCombo.setWidthFull();

        VerticalLayout configContainer = new VerticalLayout();
        configContainer.setPadding(false);
        configContainer.setSpacing(true);
        configContainer.addClassName("dialog-task-config");

        Button deleteXButton = new Button(new Icon(VaadinIcon.CLOSE_SMALL));
        deleteXButton.addThemeVariants(ButtonVariant.LUMO_ERROR, ButtonVariant.LUMO_TERTIARY);
        deleteXButton.addClassName("dialog-floating-delete");
        deleteXButton.addClickListener(e -> removeTaskRow(taskContainer));

        HorizontalLayout headerRow = new HorizontalLayout(dragHandle, summaryRow, taskTypeCombo, deleteXButton);
        headerRow.setAlignItems(FlexComponent.Alignment.START);
        headerRow.setWidthFull();
        headerRow.setFlexGrow(1, taskTypeCombo);

        taskContainer.add(headerRow, configContainer);

        setupDragAndDrop(taskContainer);

        final BaseTask[] currentTask = { task };

        // Set the combo value BEFORE registering the listener
        if (initialTaskType != null) {
            taskTypeCombo.setValue(initialTaskType);
        }

        // 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.setOptional(oldTask.isOptional());
                newTask.setCompleted(oldTask.isCompleted());
                newTask.setCompletedAt(oldTask.getCompletedAt());
                newTask.setCompletedBy(oldTask.getCompletedBy());

                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 -> {
                }
                }

                int index = tasksState.indexOf(oldTask);
                if (index >= 0) {
                    newTask.setTaskOrder(index);
                    tasksState.set(index, newTask);
                    currentTask[0] = newTask;
                }

                updateTaskConfiguration(configContainer, newTask);
                updateDragSummary(summaryRow, selectedType, newTask);
            }
        });

        // Render the UI with the loaded task
        updateTaskConfiguration(configContainer, task);
        updateDragSummary(summaryRow, initialTaskType, task);

        tasksList.add(taskContainer);
        updateTaskDeleteAvailability();
    }

    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 HorizontalLayout createDragSummary(String typeName, String description) {
        Span typeLabel = new Span(typeName);
        typeLabel.addClassName("task-type-label");
        Span descLabel = new Span(description != null && !description.isBlank() ? " — " + description : "");
        descLabel.addClassName("task-desc-label");
        HorizontalLayout layout = new HorizontalLayout(typeLabel, descLabel);
        layout.setSpacing(false);
        layout.setPadding(false);
        layout.setAlignItems(FlexComponent.Alignment.CENTER);
        return layout;
    }

    private void updateDragSummary(HorizontalLayout summaryRow, TaskType taskType, BaseTask task) {
        summaryRow.getChildren()
                .filter(Span.class::isInstance)
                .map(Span.class::cast)
                .forEach(span -> {
                    if (span.getClassNames().contains("task-type-label")) {
                        span.setText(taskType != null ? taskType.getDisplayName() : "");
                    } else if (span.getClassNames().contains("task-desc-label")) {
                        String desc = task.getDescription();
                        span.setText(desc != null && !desc.isBlank() ? " — " + desc : "");
                    }
                });
    }

    private void clearAllDropIndicators() {
        if (tasksList == null) {
            return;
        }
        tasksList.removeClassName("tasks-reordering");
        tasksList.getChildren()
                .filter(VerticalLayout.class::isInstance)
                .map(VerticalLayout.class::cast)
                .forEach(c -> {
                    c.removeClassName("drag-over-top");
                    c.removeClassName("drag-over-bottom");
                    c.removeClassName("dragging");
                });
    }

    private void setupDragAndDrop(VerticalLayout taskContainer) {
        DragSource<VerticalLayout> dragSource = DragSource.create(taskContainer);
        dragSource.setEffectAllowed(EffectAllowed.MOVE);
        dragSource.addDragStartListener(e -> {
            draggedTaskContainer = taskContainer;
            taskContainer.addClassName("dragging");
            if (tasksList != null) {
                // Update all summaries with latest description values before compressing
                List<com.vaadin.flow.component.Component> rows = tasksList.getChildren().toList();
                for (int i = 0; i < rows.size() && i < tasksState.size(); i++) {
                    if (rows.get(i) instanceof VerticalLayout row) {
                        row.getChildren()
                                .filter(HorizontalLayout.class::isInstance)
                                .map(HorizontalLayout.class::cast)
                                .findFirst()
                                .ifPresent(headerRow -> headerRow.getChildren()
                                        .filter(HorizontalLayout.class::isInstance)
                                        .map(HorizontalLayout.class::cast)
                                        .filter(c -> c.getClassNames().contains("dialog-task-summary"))
                                        .findFirst()
                                        .ifPresent(summary -> {
                                            int idx = rows.indexOf(row);
                                            if (idx >= 0 && idx < tasksState.size()) {
                                                BaseTask t = tasksState.get(idx);
                                                TaskType tt = getTaskTypeFromTask(t);
                                                updateDragSummary(summary, tt, t);
                                            }
                                        }));
                    }
                }
                tasksList.addClassName("tasks-reordering");
            }
        });
        dragSource.addDragEndListener(e -> {
            draggedTaskContainer = null;
            clearAllDropIndicators();
        });

        DropTarget<VerticalLayout> dropTarget = DropTarget.create(taskContainer);
        dropTarget.setDropEffect(DropEffect.MOVE);
        dropTarget.addDropListener(e -> {
            if (draggedTaskContainer != null && draggedTaskContainer != taskContainer) {
                moveTaskRow(draggedTaskContainer, taskContainer);
            }
            clearAllDropIndicators();
        });

        // Client-side drag events with position detection and no-op suppression
        taskContainer.getElement().executeJs(
                "const el = this;"
                        + "function clearIndicators() {"
                        + "  var p = el.parentElement;"
                        + "  if (p) p.querySelectorAll('.drag-over-top, .drag-over-bottom').forEach("
                        + "    function(c) { c.classList.remove('drag-over-top', 'drag-over-bottom'); });"
                        + "}"
                        + "function getSiblings() {"
                        + "  return Array.from(el.parentElement.children).filter("
                        + "    function(c) { return c.classList.contains('dialog-task-card'); });"
                        + "}"
                        + "el.addEventListener('dragstart', function() {"
                        + "  el.parentElement.__draggedEl = el;"
                        + "});"
                        + "el.addEventListener('dragend', function() {"
                        + "  el.parentElement.__draggedEl = null;"
                        + "});"
                        + "el.addEventListener('dragover', function(e) {"
                        + "  e.preventDefault();"
                        + "  var dragged = el.parentElement.__draggedEl;"
                        + "  if (!dragged || dragged === el) { clearIndicators(); return; }"
                        + "  var cards = getSiblings();"
                        + "  var dragIdx = cards.indexOf(dragged);"
                        + "  var myIdx = cards.indexOf(el);"
                        + "  clearIndicators();"
                        + "  var rect = el.getBoundingClientRect();"
                        + "  var midY = rect.top + rect.height / 2;"
                        + "  if (e.clientY < midY) {"
                        + "    if (myIdx !== dragIdx + 1) el.classList.add('drag-over-top');"
                        + "  } else {"
                        + "    if (myIdx !== dragIdx - 1) el.classList.add('drag-over-bottom');"
                        + "  }"
                        + "});"
                        + "el.addEventListener('dragleave', function() {"
                        + "  el.classList.remove('drag-over-top', 'drag-over-bottom');"
                        + "});"
                        + "el.addEventListener('drop', function() {"
                        + "  clearIndicators();"
                        + "});");
    }

    private void moveTaskRow(VerticalLayout source, VerticalLayout target) {
        List<com.vaadin.flow.component.Component> rows = tasksList.getChildren().toList();
        int fromIndex = rows.indexOf(source);
        int toIndex = rows.indexOf(target);
        if (fromIndex < 0 || toIndex < 0 || fromIndex == toIndex) {
            return;
        }

        // Reorder tasksState
        BaseTask movedTask = tasksState.remove(fromIndex);
        tasksState.add(toIndex, movedTask);

        // Reorder UI: remove all, re-add in new order
        List<com.vaadin.flow.component.Component> rowList = new ArrayList<>(rows);
        com.vaadin.flow.component.Component movedRow = rowList.remove(fromIndex);
        rowList.add(toIndex, movedRow);

        tasksList.removeAll();
        rowList.forEach(tasksList::add);

        // Update taskOrder values
        reorderTasksAfterDeletion();
    }

    private void reorderTasksAfterDeletion() {
        for (int i = 0; i < tasksState.size(); i++) {
            BaseTask task = tasksState.get(i);
            if (task != null) {
                task.setTaskOrder(i);
            }
        }
    }

    private void removeTaskRow(VerticalLayout taskContainer) {
        if (tasksList == null) {
            return;
        }

        List<com.vaadin.flow.component.Component> taskRows = tasksList.getChildren().toList();
        int idx = taskRows.indexOf(taskContainer);
        if (idx < 0) {
            return;
        }

        if (idx < tasksState.size()) {
            tasksState.remove(idx);
        }
        tasksList.remove(taskContainer);
        reorderTasksAfterDeletion();
        updateTaskDeleteAvailability();
    }

    private void ensureTrailingSignatureTask() {
        BaseTask lastTask = tasksState.isEmpty() ? null : tasksState.get(tasksState.size() - 1);
        if (lastTask instanceof SignatureTask) {
            return;
        }

        SignatureTask signatureTask = new SignatureTask();
        signatureTask.setTaskOrder(tasksState.size());
        tasksState.add(signatureTask);
        if (tasksList != null) {
            createTaskRowFromTask(signatureTask);
        }
    }

    private void updateTaskDeleteAvailability() {
        if (tasksList == null) {
            return;
        }

        boolean deletable = tasksList.getChildren().count() > 1;
        tasksList.getChildren()
                .filter(VerticalLayout.class::isInstance)
                .map(VerticalLayout.class::cast)
                .forEach(taskContainer -> taskContainer.getChildren()
                        .filter(HorizontalLayout.class::isInstance)
                        .map(HorizontalLayout.class::cast)
                        .findFirst()
                        .ifPresent(headerRow -> headerRow.getChildren()
                                .filter(Button.class::isInstance)
                                .map(Button.class::cast)
                                .filter(button -> button.getClassNames().contains("dialog-floating-delete"))
                                .findFirst()
                                .ifPresent(button -> button.setEnabled(deletable))));
    }

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

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

        switch (taskType) {
        case CONFIRMATION:
            TextField descriptionField = new TextField(translationHelper.getTranslation("addjob.tasks.description"));
            descriptionField.setPlaceholder(translationHelper.getTranslation("addjob.tasks.description.placeholder"));
            descriptionField.setWidthFull();
            descriptionField.setRequiredIndicatorVisible(true);
            descriptionField.setValue(task.getDescription() != null ? task.getDescription() : "");
            descriptionField.addValueChangeListener(ev -> {
                task.setDescription(ev.getValue());
                applyErrorStyling(descriptionField, ev.getValue() == null || ev.getValue().trim().isEmpty());
                validateRequiredFields();
            });
            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)");
            }

            TextField buttonTextField = new TextField(translationHelper.getTranslation("addjob.tasks.buttontext"));
            buttonTextField.setPlaceholder(translationHelper.getTranslation("addjob.tasks.buttontext.placeholder"));
            buttonTextField.setWidthFull();
            buttonTextField.setRequiredIndicatorVisible(true);
            ConfirmationTask confirmationTask = (ConfirmationTask) task;
            buttonTextField.setValue(confirmationTask.getButtonText() != null ? confirmationTask.getButtonText() : "");
            buttonTextField.addValueChangeListener(ev -> {
                confirmationTask.setButtonText(ev.getValue());
                applyErrorStyling(buttonTextField, ev.getValue() == null || ev.getValue().trim().isEmpty());
                validateRequiredFields();
            });
            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:
            TextField signatureNoteField = new TextField(
                    translationHelper.getTranslation("addjob.tasks.signature.notelabel"));
            signatureNoteField.setPlaceholder(
                    translationHelper.getTranslation("addjob.tasks.signature.notelabel.placeholder"));
            signatureNoteField.setWidthFull();
            signatureNoteField.setValue(task.getDescription() != null ? task.getDescription() : "");
            signatureNoteField.addValueChangeListener(ev -> task.setDescription(ev.getValue()));
            configContainer.add(signatureNoteField);
            break;

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

            H3 todoTitle = new H3(translationHelper.getTranslation("addjob.tasks.todolist.title"));
            todoTitle.getStyle().set("margin", "0");
            todoContainer.add(todoTitle);

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

            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(translationHelper.getTranslation("addjob.tasks.todolist.item.placeholder"));
                todoField.setWidth("100%");
                todoField.setRequiredIndicatorVisible(true);
                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);
                    validateRequiredFields();
                });
            };

            Button addTodoBtn = new Button(translationHelper.getTranslation("addjob.tasks.todolist.add"),
                    new Icon(VaadinIcon.PLUS));
            addTodoBtn.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
            addTodoBtn.addClickListener(e -> addTodoItem.accept(null));

            if (task instanceof TodoListTask todoTask) {
                if (todoTask.getTodoItems() != null && !todoTask.getTodoItems().isEmpty()) {
                    for (String todoText : todoTask.getTodoItems()) {
                        HorizontalLayout todoRow = new HorizontalLayout();
                        todoRow.setWidthFull();
                        todoRow.setAlignItems(FlexComponent.Alignment.END);

                        TextField todoField = new TextField();
                        todoField.setPlaceholder(
                                translationHelper.getTranslation("addjob.tasks.todolist.item.placeholder"));
                        todoField.setWidth("100%");
                        todoField.setRequiredIndicatorVisible(true);
                        todoField.setValue(todoText != null ? todoText : "");
                        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 {
                    addTodoItem.accept(null);
                }
            } else {
                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(translationHelper.getTranslation("addjob.tasks.photo.min"));
            minPhotos.setPlaceholder("1");
            minPhotos.setMin(1);
            minPhotos.setValue(photoTask.getMinPhotoCount() != null ? photoTask.getMinPhotoCount() : 1);

            IntegerField maxPhotos = new IntegerField(translationHelper.getTranslation("addjob.tasks.photo.max"));
            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(translationHelper.getTranslation("addjob.tasks.barcode.min"));
            minBarcodes.setPlaceholder("1");
            minBarcodes.setMin(1);
            minBarcodes.setValue(barcodeTask.getMinBarcodeCount() != null ? barcodeTask.getMinBarcodeCount() : 1);

            IntegerField maxBarcodes = new IntegerField(translationHelper.getTranslation("addjob.tasks.barcode.max"));
            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(translationHelper.getTranslation("addjob.tasks.comment.label"));
            commentTextField.setPlaceholder(translationHelper.getTranslation("addjob.tasks.comment.placeholder"));
            commentTextField.setWidthFull();
            commentTextField.setValue(commentTask.getCommentText() != null ? commentTask.getCommentText() : "");
            commentTextField.addValueChangeListener(ev -> commentTask.setCommentText(ev.getValue()));

            Checkbox requiredCheckbox = new Checkbox(translationHelper.getTranslation("addjob.tasks.comment.required"));
            requiredCheckbox.setValue(commentTask.isRequired());
            requiredCheckbox.addValueChangeListener(ev -> commentTask.setRequired(ev.getValue()));

            configContainer.add(commentTextField, requiredCheckbox);
            break;

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

        // Optional checkbox – applies to all task types
        Checkbox optionalCheckbox = new Checkbox(translationHelper.getTranslation("addjob.tasks.optional"));
        optionalCheckbox.setValue(task.isOptional());
        optionalCheckbox.addValueChangeListener(ev -> task.setOptional(ev.getValue()));
        configContainer.add(optionalCheckbox);
    }

    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(item -> item != null).toList();

        if (task instanceof TodoListTask todoTask) {
            todoTask.setTodoItems(new ArrayList<>(todoItems));
        }
    }

    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;
    }

    private BaseTask createTaskCopy(BaseTask original) {
        BaseTask copy = null;

        if (original instanceof ConfirmationTask origTask) {
            copy = new ConfirmationTask();
            if (origTask.getButtonText() != null) {
                ((ConfirmationTask) copy).setButtonText(origTask.getButtonText());
            }
        } else if (original instanceof SignatureTask) {
            copy = new SignatureTask();
        } else if (original instanceof TodoListTask origTask) {
            copy = new TodoListTask();
            if (origTask.getTodoItems() != null) {
                ((TodoListTask) copy).setTodoItems(new ArrayList<>(origTask.getTodoItems()));
            }
        } else if (original instanceof PhotoTask origTask) {
            copy = new PhotoTask(origTask.getMinPhotoCount() != null ? origTask.getMinPhotoCount() : 1,
                    origTask.getMaxPhotoCount() != null ? origTask.getMaxPhotoCount() : 10);
        } else if (original instanceof BarcodeTask origTask) {
            copy = new BarcodeTask(origTask.getMinBarcodeCount() != null ? origTask.getMinBarcodeCount() : 1,
                    origTask.getMaxBarcodeCount() != null ? origTask.getMaxBarcodeCount() : 10);
        } else if (original instanceof CommentTask origTask) {
            copy = new CommentTask(origTask.getCommentText() != null ? origTask.getCommentText() : "",
                    origTask.isRequired());
        }

        if (copy != null) {
            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;
    }

    private void saveTasksAsTemplate(TemplateSaveCallback templateSaveCallback,
            ComboBox<TaskTemplate> templateComboBox) {
        if (templateSaveCallback == null) {
            return;
        }

        if (tasksState.isEmpty()) {
            Notification.show(translationHelper.getTranslation("addjob.tasks.template.no.tasks"), 3000,
                    Notification.Position.BOTTOM_END);
            return;
        }

        Dialog dialog = DialogStylingHelper
                .createStyledDialog(translationHelper.getTranslation("addjob.tasks.template.save.title"), "460px");
        dialog.setCloseOnOutsideClick(false);

        VerticalLayout dialogLayout = DialogStylingHelper.createContentLayout("340px");

        TextField templateNameField = new TextField(translationHelper.getTranslation("addjob.tasks.template.name"));
        templateNameField.setPlaceholder(translationHelper.getTranslation("addjob.tasks.template.name.placeholder"));
        templateNameField.setWidthFull();
        templateNameField.setRequiredIndicatorVisible(true);

        Button saveButton = new Button(translationHelper.getTranslation("button.savechanges"));
        saveButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        saveButton.addClickListener(e -> {
            String templateName = templateNameField.getValue();
            if (templateName == null || templateName.trim().isEmpty()) {
                Notification.show(translationHelper.getTranslation("addjob.tasks.template.name.required"), 3000,
                        Notification.Position.BOTTOM_END);
                return;
            }

            List<BaseTask> tasksCopy = new ArrayList<>();
            for (BaseTask task : tasksState) {
                BaseTask taskCopy = createTaskCopy(task);
                tasksCopy.add(taskCopy);
            }

            templateSaveCallback.saveTemplate(templateName.trim(), tasksCopy);
            dialog.close();
        });

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

        dialogLayout.add(templateNameField);
        dialog.add(DialogStylingHelper.wrapContent(dialogLayout));
        dialog.getFooter().add(cancelButton, saveButton);
        dialog.open();
    }

    private void loadTasksFromTemplate(TaskTemplate template, ComboBox<TaskTemplate> templateComboBox) {
        Dialog confirmDialog = DialogStylingHelper
                .createStyledDialog(translationHelper.getTranslation("addjob.tasks.template.load.title"), "560px");
        confirmDialog.setCloseOnOutsideClick(false);
        confirmDialog.addDialogCloseActionListener(e -> templateComboBox.clear());

        VerticalLayout dialogContent = DialogStylingHelper.createContentLayout("420px");
        dialogContent.add(new Span(
                translationHelper.getTranslation("addjob.tasks.template.load.text", template.getTemplateName())));

        Button cancelButton = new Button(translationHelper.getTranslation("button.cancel"), e -> {
            templateComboBox.clear();
            confirmDialog.close();
        });
        cancelButton.addThemeVariants(ButtonVariant.LUMO_TERTIARY);

        Button confirmButton = new Button(translationHelper.getTranslation("addjob.tasks.template.load.confirm"), e -> {
            tasksState.clear();
            tasksList.removeAll();

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

            ensureTrailingSignatureTask();
            templateComboBox.clear();
            validateRequiredFields();

            Notification.show(
                    translationHelper.getTranslation("addjob.tasks.template.loaded", template.getTemplateName()), 3000,
                    Notification.Position.BOTTOM_END);
            confirmDialog.close();
        });
        confirmButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);

        confirmDialog.add(DialogStylingHelper.wrapContent(dialogContent));
        confirmDialog.getFooter().add(cancelButton, confirmButton);
        confirmDialog.open();
    }
}
