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

import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.checkbox.Checkbox;
import com.vaadin.flow.component.combobox.ComboBox;
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.textfield.TextField;
import de.assecutor.votianlt.model.Customer;
import de.assecutor.votianlt.model.DeliveryStation;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * A self-contained tile for one delivery station in the AddJob form. Contains
 * all address fields, delivery date/time, and a save-address checkbox.
 */
public class DeliveryStationTile extends VerticalLayout {

    public interface ChangeListener {
        void onChanged();
    }

    public interface DeleteListener {
        void onDelete(DeliveryStationTile tile);
    }

    public interface CollapseListener {
        void onCollapseChanged(boolean collapsed);
    }

    private final int stationNumber;

    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 street;
    private final TextField houseNumber;
    private final TextField addressAddition;
    private final TextField zip;
    private final TextField city;
    private final Checkbox saveAddress;
    private final H3 title;
    private final Map<String, Customer> companyAddressOptions = new LinkedHashMap<>();

    private ChangeListener changeListener;
    private DeleteListener deleteListener;
    private CollapseListener collapseListener;

    private boolean collapsed = false;
    private Button collapseButton;
    private VerticalLayout collapsedContent;
    private List<Component> expandedOnlyComponents;

    public DeliveryStationTile(int stationNumber, boolean removable, List<Customer> customers,
            TranslationHelper translationHelper) {
        this.stationNumber = stationNumber;

        setSpacing(true);
        setPadding(true);
        setWidthFull();
        addClassName("delivery-station-card");
        getStyle().set("min-width", "0");
        getStyle().set("box-sizing", "border-box");

        // Header with title, collapse button and delete button on one line
        title = new H3(translationHelper.getTranslation("addjob.station.delivery", stationNumber));
        title.getStyle().set("margin", "0").set("flex-grow", "1");

        collapseButton = new Button(new Icon(VaadinIcon.ANGLE_DOUBLE_LEFT));
        collapseButton.addThemeVariants(ButtonVariant.LUMO_TERTIARY_INLINE);
        collapseButton.getStyle().set("cursor", "pointer");
        collapseButton.addClickListener(e -> toggleCollapse());

        Button deleteButton = new Button(new Icon(VaadinIcon.CLOSE_SMALL));
        deleteButton.addThemeVariants(ButtonVariant.LUMO_ERROR, ButtonVariant.LUMO_TERTIARY);
        if (removable) {
            deleteButton.addClickListener(e -> {
                if (deleteListener != null) {
                    deleteListener.onDelete(this);
                }
            });
        } else {
            deleteButton.getStyle().set("visibility", "hidden");
        }

        HorizontalLayout titleLayout = new HorizontalLayout();
        titleLayout.setWidthFull();
        titleLayout.setDefaultVerticalComponentAlignment(FlexComponent.Alignment.CENTER);
        titleLayout.add(title, collapseButton, deleteButton);

        add(titleLayout);

        // 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, translationHelper);
        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();
        add(salutation);

        // Name fields
        firstName = new TextField(translationHelper.getTranslation("profile.firstname"));
        firstName.setPlaceholder(translationHelper.getTranslation("profile.firstname"));
        firstName.setRequiredIndicatorVisible(true);
        firstName.setWidthFull();
        add(firstName);

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

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

        // Street + house number
        street = new TextField(translationHelper.getTranslation("profile.street"));
        street.setPlaceholder(translationHelper.getTranslation("addjob.address.delivery.street.placeholder"));
        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);
        streetLayout.getStyle().set("flex-wrap", "wrap");
        street.getStyle().set("flex", "3 1 150px").set("min-width", "0");
        houseNumber.getStyle().set("flex", "1 1 60px").set("min-width", "0");
        streetLayout.add(street, houseNumber);
        add(streetLayout);

        // Address addition
        addressAddition = new TextField(translationHelper.getTranslation("profile.addressadd"));
        addressAddition
                .setPlaceholder(translationHelper.getTranslation("addjob.address.delivery.addition.placeholder"));
        addressAddition.setWidthFull();
        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.placeholder.delivery"));
        city.setRequiredIndicatorVisible(true);

        HorizontalLayout zipCityLayout = new HorizontalLayout();
        zipCityLayout.setWidthFull();
        zipCityLayout.setSpacing(true);
        zipCityLayout.getStyle().set("flex-wrap", "wrap");
        zip.getStyle().set("flex", "1 1 80px").set("min-width", "0");
        city.getStyle().set("flex", "3 1 150px").set("min-width", "0");
        zipCityLayout.add(zip, city);
        add(zipCityLayout);

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

        // Register change listeners on all fields
        setupChangeListeners();

        // Store references to expanded-mode components (excluding titleLayout which
        // stays visible)
        expandedOnlyComponents = getChildren().filter(c -> c != titleLayout).toList();

        getStyle().set("transition", "opacity 0.2s ease");

        // Collapsed content (initially hidden)
        collapsedContent = new VerticalLayout();
        collapsedContent.setPadding(false);
        collapsedContent.setSpacing(false);
        collapsedContent.getStyle().set("gap", "var(--lumo-space-xs)");
        collapsedContent.setVisible(false);
        add(collapsedContent);
    }

    private void setupChangeListeners() {
        TextField[] textFields = { firstName, lastName, street, houseNumber, zip, city, phone, addressAddition };
        for (TextField field : textFields) {
            field.addValueChangeListener(e -> {
                updateFieldStyling(field);
                fireChanged();
            });
        }

        company.addValueChangeListener(e -> fireChanged());
        salutation.addValueChangeListener(e -> fireChanged());
    }

    private void fireChanged() {
        if (changeListener != null) {
            changeListener.onChanged();
        }
    }

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

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

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

            Customer customer = companyAddressOptions.get(selectedAddress);
            if (customer != null) {
                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.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());

            }
        });

        companyField.addCustomValueSetListener(event -> {
            companyField.setValue(event.getDetail());
        });
    }

    /**
     * Updates the station number displayed in the title.
     */
    public void updateStationNumber(int newNumber) {
        title.setText(getTranslation("addjob.station.delivery", newNumber));
    }

    /**
     * Collects all field values into a DeliveryStation object.
     */
    public DeliveryStation getDeliveryStation() {
        DeliveryStation station = new DeliveryStation();
        station.setCompany(CustomerAddressLabelHelper.resolveCompanyValue(companyAddressOptions, company.getValue()));
        station.setSalutation(salutation.getValue());
        station.setFirstName(firstName.getValue());
        station.setLastName(lastName.getValue());
        station.setPhone(phone.getValue());
        station.setStreet(street.getValue());
        station.setHouseNumber(houseNumber.getValue());
        station.setAddressAddition(addressAddition.getValue());
        station.setZip(zip.getValue());
        station.setCity(city.getValue());
        return station;
    }

    /**
     * Populates the tile fields from an existing DeliveryStation.
     */
    public void setDeliveryStation(DeliveryStation station) {
        if (station == null)
            return;
        if (station.getCompany() != null)
            company.setValue(station.getCompany());
        if (station.getSalutation() != null)
            salutation.setValue(station.getSalutation());
        if (station.getFirstName() != null)
            firstName.setValue(station.getFirstName());
        if (station.getLastName() != null)
            lastName.setValue(station.getLastName());
        if (station.getPhone() != null)
            phone.setValue(station.getPhone());
        if (station.getStreet() != null)
            street.setValue(station.getStreet());
        if (station.getHouseNumber() != null)
            houseNumber.setValue(station.getHouseNumber());
        if (station.getAddressAddition() != null)
            addressAddition.setValue(station.getAddressAddition());
        if (station.getZip() != null)
            zip.setValue(station.getZip());
        if (station.getCity() != null)
            city.setValue(station.getCity());
    }

    /**
     * Checks if all required address fields are filled.
     */
    public boolean hasValidationErrors() {
        return isFieldEmpty(firstName) || isFieldEmpty(lastName) || isFieldEmpty(street) || isFieldEmpty(houseNumber)
                || isFieldEmpty(zip) || isFieldEmpty(city);
    }

    /**
     * Applies error styling to empty required fields.
     */
    public void highlightErrors() {
        TextField[] required = { firstName, lastName, street, houseNumber, zip, city };
        for (TextField field : required) {
            updateFieldStyling(field);
        }
    }

    /**
     * Clears all fields in this tile.
     */
    public void clearFields() {
        company.clear();
        salutation.clear();
        firstName.clear();
        lastName.clear();
        phone.clear();
        street.clear();
        houseNumber.clear();
        addressAddition.clear();
        zip.clear();
        city.clear();
        saveAddress.setValue(true);
    }

    /**
     * Returns the street value for address validation.
     */
    public String getStreetValue() {
        return getValueOrEmpty(street);
    }

    /**
     * Returns the house number value for address validation.
     */
    public String getHouseNumberValue() {
        return getValueOrEmpty(houseNumber);
    }

    /**
     * Returns the zip value for address validation.
     */
    public String getZipValue() {
        return getValueOrEmpty(zip);
    }

    /**
     * Returns the city value for address validation.
     */
    public String getCityValue() {
        return getValueOrEmpty(city);
    }

    /**
     * Checks if the delivery address has enough data for validation.
     */
    public boolean hasAddressForValidation() {
        return !getStreetValue().isEmpty() && !getZipValue().isEmpty() && !getCityValue().isEmpty();
    }

    public void setChangeListener(ChangeListener listener) {
        this.changeListener = listener;
    }

    public void setDeleteListener(DeleteListener listener) {
        this.deleteListener = listener;
    }

    public void setCollapseListener(CollapseListener listener) {
        this.collapseListener = listener;
    }

    public boolean isCollapsed() {
        return collapsed;
    }

    /**
     * Returns whether the user wants to save this address as a customer.
     */
    public boolean isSaveAddressChecked() {
        return saveAddress.getValue();
    }

    public int getStationNumber() {
        return stationNumber;
    }

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

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

    private void updateFieldStyling(TextField field) {
        boolean isEmpty = isFieldEmpty(field);
        if (isEmpty && field.isRequiredIndicatorVisible()) {
            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");
        }
    }

    private void toggleCollapse() {
        collapsed = !collapsed;
        if (collapsed) {
            updateCollapsedContent();
            expandedOnlyComponents.forEach(c -> c.setVisible(false));
            collapsedContent.setVisible(true);
            collapseButton.setIcon(new Icon(VaadinIcon.ANGLE_DOUBLE_RIGHT));
        } else {
            expandedOnlyComponents.forEach(c -> c.setVisible(true));
            collapsedContent.setVisible(false);
            collapseButton.setIcon(new Icon(VaadinIcon.ANGLE_DOUBLE_LEFT));
        }
        if (collapseListener != null) {
            collapseListener.onCollapseChanged(collapsed);
        }
    }

    private void updateCollapsedContent() {
        collapsedContent.removeAll();

        addCollapsedLine(company.getValue());

        String name = (getValueOrEmpty(firstName) + " " + getValueOrEmpty(lastName)).trim();
        addCollapsedLine(name);

        String streetLine = (getValueOrEmpty(street) + " " + getValueOrEmpty(houseNumber)).trim();
        addCollapsedLine(streetLine);

        String zipCityLine = (getValueOrEmpty(zip) + " " + getValueOrEmpty(city)).trim();
        addCollapsedLine(zipCityLine);
    }

    private void addCollapsedLine(String text) {
        if (text != null && !text.trim().isEmpty()) {
            Span span = new Span(text);
            span.getStyle().set("font-size", "var(--lumo-font-size-xs)").set("word-break", "break-word").set("color",
                    "var(--lumo-secondary-text-color)");
            collapsedContent.add(span);
        }
    }

    /**
     * Functional interface for accessing translations from the parent view.
     */
    @FunctionalInterface
    public interface TranslationHelper {
        String getTranslation(String key, Object... params);
    }
}
