import java.util.List;
import java.util.concurrent.TimeUnit;

//import org.junit.Test;
import org.junit.jupiter.api.Test;
import org.testfx.api.FxRobot;
import org.testfx.framework.junit.ApplicationTest;
import org.testfx.util.WaitForAsyncUtils;

import javafx.collections.FXCollections;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class ListViewItemsTest extends ApplicationTest
{

    private BorderPane rootPane;

    @Override
    public void start(Stage stage)
    {
        rootPane = new BorderPane();
        rootPane.setId("rootPane");
        rootPane.getStyleClass().add("root");

        Scene scene = new Scene(rootPane);
        stage.setTitle("ListView Items Test");
        stage.setScene(scene);
        stage.setWidth(500);
        stage.setHeight(300);
        stage.show();
        stage.toFront();
        stage.centerOnScreen();
    }

    @Test
    public void testItemsPropertyChangeNotFired()
    {
        System.out.println("Testing Items property change not fired...");

        ListView<String> listView = new ListView<>();
        ScrollPane scrollPane = new ScrollPane(listView);
        scrollPane.setFitToHeight(true);
        scrollPane.setFitToWidth(true);

        Label statusLabel = new Label();
        statusLabel.setText("Nothing to report (yet).");
        statusLabel.setStyle("-fx-text-fill: black;");

        FxRobot robot = new FxRobot();
        robot.interact(() -> {
            rootPane.setCenter(scrollPane);
            rootPane.setBottom(statusLabel);
        });
        WaitForAsyncUtils.sleep(3333L, TimeUnit.MILLISECONDS);

        robot.interact(() -> {
            statusLabel.setText("Adding change listner...");
            listView.itemsProperty().addListener((s, o, n) -> {
                statusLabel.setStyle("-fx-text-fill: royalblue;");
                statusLabel.setText("Items changed: " + o + " -> " + n);
            });
        });
        WaitForAsyncUtils.sleep(3333L, TimeUnit.MILLISECONDS);

        // ---- First Problem: adding an empty list ------------------------------------------------
        robot.interact(() -> statusLabel.setText("Setting an empty list to the list view..."));
        WaitForAsyncUtils.sleep(3333L, TimeUnit.MILLISECONDS);

        robot.interact(() -> listView.setItems(FXCollections.observableList(List.of())));
        WaitForAsyncUtils.sleep(3333L, TimeUnit.MILLISECONDS);

        robot.interact(() -> {
            statusLabel.setStyle("-fx-text-fill: crimson;");
            statusLabel.setText(
                    "No change notified: the items count is the same as before, but the list instance is different.");
        });
        WaitForAsyncUtils.sleep(3333L, TimeUnit.MILLISECONDS);
        // -----------------------------------------------------------------------------------------

        robot.interact(() -> {
            statusLabel.setStyle("-fx-text-fill: black;");
            statusLabel.setText("Setting a not-empty list to the list view...");
        });
        WaitForAsyncUtils.sleep(3333L, TimeUnit.MILLISECONDS);

        robot.interact(() -> {
            listView.setItems(FXCollections.observableList(
                    List.of("Roma", "Torino", "Milano", "Napoli", "Firenze")));
        });
        WaitForAsyncUtils.sleep(3333L, TimeUnit.MILLISECONDS);

        robot.interact(() -> {
            statusLabel.setStyle("-fx-text-fill: forestgreen;");
            statusLabel.setText("The change was notified.");
        });
        WaitForAsyncUtils.sleep(3333L, TimeUnit.MILLISECONDS);

        // ---- Second Problem: adding different list with the same elements -----------------------
        robot.interact(() -> {
            statusLabel.setStyle("-fx-text-fill: black;");
            statusLabel.setText(
                    "Setting a not-empty list containing the same elements to the list view...");
        });
        WaitForAsyncUtils.sleep(3333L, TimeUnit.MILLISECONDS);

        robot.interact(() -> {
            listView.setItems(FXCollections.observableList(
                    List.of("Roma", "Torino", "Milano", "Napoli", "Firenze")));
        });
        WaitForAsyncUtils.sleep(3333L, TimeUnit.MILLISECONDS);

        robot.interact(() -> {
            statusLabel.setStyle("-fx-text-fill: crimson;");
            statusLabel.setText(
                    "No change notified: the items count is the same as before, but the list instance is different.");
        });
        WaitForAsyncUtils.sleep(3333L, TimeUnit.MILLISECONDS);
        // -----------------------------------------------------------------------------------------

        robot.interact(() -> {
            statusLabel.setStyle("-fx-text-fill: black;");
            statusLabel.setText("Setting an empty list to the list view...");
        });
        WaitForAsyncUtils.sleep(3333L, TimeUnit.MILLISECONDS);

        robot.interact(() -> listView.setItems(FXCollections.observableList(List.of())));
        WaitForAsyncUtils.sleep(3333L, TimeUnit.MILLISECONDS);

        robot.interact(() -> {
            statusLabel.setStyle("-fx-text-fill: forestgreen;");
            statusLabel.setText("The change was notified.");
        });
        WaitForAsyncUtils.sleep(3333L, TimeUnit.MILLISECONDS);

        // ---- First Problem: adding a different empty list ---------------------------------------
        robot.interact(() -> {
            statusLabel.setStyle("-fx-text-fill: black;");
            statusLabel.setText("Setting another empty list to the list view...");
        });
        WaitForAsyncUtils.sleep(3333L, TimeUnit.MILLISECONDS);

        robot.interact(() -> listView.setItems(FXCollections.observableList(List.of())));
        WaitForAsyncUtils.sleep(3333L, TimeUnit.MILLISECONDS);

        robot.interact(() -> {
            statusLabel.setStyle("-fx-text-fill: crimson;");
            statusLabel.setText(
                    "No change notified: the items count is the same as before, but the list instance is different.");
        });
        WaitForAsyncUtils.sleep(3333L, TimeUnit.MILLISECONDS);
        // -----------------------------------------------------------------------------------------
    }

}
