
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Control;

import java.util.Map;
import java.util.WeakHashMap;

/*
    Author: T.Chudyk
    This example class comes from https://tchudyk.com/
 */
public class AppThemes {

    private final ObservableList<Theme> themes = FXCollections.observableArrayList();
    private final ObjectProperty<Theme> selectedTheme = new SimpleObjectProperty<>();
    private final Map<Scene, Boolean> scenes = new WeakHashMap<>();

    public AppThemes() {
        themes.addListener((ListChangeListener<Theme>) c -> {
            if (!c.next()) {
                return;
            }
            if (c.wasAdded() && selectedTheme.get() == null) {
                selectedTheme.set(c.getAddedSubList().getFirst());
            } else if (themes.isEmpty()) {
                selectedTheme.set(null);
            }
        });
        selectedTheme.addListener((observable, oldValue, newValue) -> {
            scenes.keySet().forEach(scene -> applyTheme(scene, newValue));
        });
    }

    public void addScene(Scene scene) {
        scenes.put(scene, true);
        applyTheme(scene, selectedTheme.get());
    }

    public AppThemes addThemes(Theme... themes) {
        this.themes.addAll(themes);
        return this;
    }

    public ObjectProperty<Theme> selectedThemeProperty() {
        return selectedTheme;
    }

    public Control createThemeControl() {
        Button button = new Button("Switch Theme");
        button.setOnAction(event -> {
            int index = themes.indexOf(selectedTheme.get());
            if (index < themes.size() - 1) {
                selectedTheme.set(themes.get(index + 1));
            } else {
                selectedTheme.set(themes.getFirst());
            }
        });
        return button;
    }

    private void applyTheme(Scene scene, Theme newTheme) {
        String customTheme = (String) scene.getProperties().get("customTheme");
        if (customTheme != null) {
            scene.getStylesheets().remove(customTheme);
        }
        if (newTheme != null) {
            scene.getStylesheets().add(newTheme.stylesheet());
            scene.getProperties().put("customTheme", newTheme.stylesheet());
        }
    }

    public record Theme(String name, String stylesheet) {
    }
}
