package io.xpipe.app.comp.base;

import io.xpipe.app.comp.RegionBuilder;
import io.xpipe.app.platform.PlatformThread;

import javafx.beans.property.Property;
import javafx.beans.property.SimpleStringProperty;
import javafx.scene.control.TextField;
import javafx.scene.control.skin.TextFieldSkin;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Rectangle;

import java.util.Objects;

public class TextFieldComp extends RegionBuilder<TextField> {

    private final Property<String> lastAppliedValue;
    private final Property<String> currentValue;
    private final boolean lazy;

    public TextFieldComp(Property<String> value) {
        this(value, false);
    }

    public TextFieldComp(Property<String> value, boolean lazy) {
        this.lastAppliedValue = value;
        this.currentValue = new SimpleStringProperty(value.getValue());
        this.lazy = lazy;
        if (!lazy) {
            currentValue.subscribe(val -> {
                if (!Objects.equals(val, value.getValue())) {
                    value.setValue(val);
                }
            });
        }
        lastAppliedValue.addListener((c, o, n) -> {
            currentValue.setValue(n);
        });
    }

    @Override
    public TextField createSimple() {
        var text = new TextField(currentValue.getValue() != null ? currentValue.getValue() : "");
        text.textProperty().addListener((c, o, n) -> {
            currentValue.setValue(n != null && n.length() > 0 ? n : null);
        });
        lastAppliedValue.addListener((c, o, n) -> {
            PlatformThread.runLaterIfNeeded(() -> {
                // Check if control value is the same. Then don't set it as that might cause bugs
                if (Objects.equals(text.getText(), n)
                        || (n == null && text.getText().isEmpty())) {
                    return;
                }

                text.setText(n);
            });
        });

        text.setOnKeyPressed(ke -> {
            if (ke.getCode().equals(KeyCode.ENTER)) {
                text.getScene().getRoot().requestFocus();
            }

            if (lazy && ke.getCode().equals(KeyCode.ENTER)) {
                lastAppliedValue.setValue(currentValue.getValue());
            }
        });

        text.focusedProperty().addListener((observable, oldValue, newValue) -> {
            if (!newValue && lazy) {
                lastAppliedValue.setValue(currentValue.getValue());
            }
        });

        // Fix caret not being visible on right side when overflowing
        text.setSkin(new TextFieldSkin(text));
        Pane pane = (Pane) text.getChildrenUnmodifiable().getFirst();
        var rec = new Rectangle();
        rec.widthProperty().bind(pane.widthProperty().add(2));
        rec.heightProperty().bind(pane.heightProperty());
        rec.setSmooth(false);
        text.getChildrenUnmodifiable().getFirst().setClip(rec);

        return text;
    }
}
