package ch.zhaw.gartenverwaltung;

import ch.zhaw.gartenverwaltung.bootstrap.AfterInject;
import ch.zhaw.gartenverwaltung.bootstrap.Inject;
import ch.zhaw.gartenverwaltung.io.PlantList;
import ch.zhaw.gartenverwaltung.io.TaskList;
import ch.zhaw.gartenverwaltung.models.Garden;
import ch.zhaw.gartenverwaltung.io.HardinessZoneNotSetException;
import ch.zhaw.gartenverwaltung.models.GardenSchedule;
import ch.zhaw.gartenverwaltung.types.Crop;
import ch.zhaw.gartenverwaltung.types.Plant;
import ch.zhaw.gartenverwaltung.types.Task;
import javafx.application.Platform;
import javafx.beans.property.ListProperty;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;

import java.io.IOException;
import java.time.LocalDate;
import java.util.List;
import java.util.Objects;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Controller class for the MySchedule.fxml file
 */
public class MyScheduleController {
    private static final Logger LOG = Logger.getLogger(MyScheduleController.class.getName());

    private Crop selectedCrop = null;

    @Inject
    private GardenSchedule gardenSchedule;
    @Inject
    private Garden garden;
    @Inject
    private PlantList plantList;

    @FXML
    private ListView<List<Task>> week_listView;

    @FXML
    private Label information_label;

    @FXML
    private ListView<Crop> scheduledPlants_listview;

    @FXML
    private void showAllTasks(ActionEvent actionEvent) throws IOException {
        gardenSchedule.getTasksUpcomingWeek();
        scheduledPlants_listview.getSelectionModel().clearSelection();
    }

    @AfterInject
    @SuppressWarnings("unused")
    public void init() throws IOException {
        setCellFactoryCropListView();
        setCellFactoryTaskListView();
        scheduledPlants_listview.itemsProperty().bind(garden.getPlantedCrops());
        ListProperty<List<Task>> taskListProperty = gardenSchedule.getWeeklyTaskListProperty();
        week_listView.itemsProperty().bind(taskListProperty);
        lookForSelectedListEntries();
        information_label.setText("");

        gardenSchedule.getTasksUpcomingWeek();
        TaskList.TaskListObserver taskListObserver = newTaskList -> {
            Platform.runLater(() -> {
                try {
                    gardenSchedule.getTasksUpcomingWeek();
                    scheduledPlants_listview.getSelectionModel().clearSelection();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            });
        };
        gardenSchedule.setTaskListObserver(taskListObserver);
    }

    /**
     * sort scheduler to selected crop
     */
    private void lookForSelectedListEntries() {
        scheduledPlants_listview.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
            selectedCrop = newValue;
            try {
                loadTaskList();
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
    }

    /**
     * set cellFactory for the crops.
     */
    private void setCellFactoryCropListView() {
        MultipleSelectionModel<Crop> selectionModel = scheduledPlants_listview.getSelectionModel();
        selectionModel.setSelectionMode(SelectionMode.MULTIPLE);
        scheduledPlants_listview.setCellFactory(param -> new ListCell<>() {
            @Override
            protected void updateItem(Crop crop, boolean empty) {
                super.updateItem(crop, empty);

                if (empty || crop == null) {
                    setText(null);
                } else {
                    try {
                        String text = plantList.getPlantById(Settings.getInstance().getCurrentHardinessZone(), crop.getPlantId())
                                .map(Plant::name)
                                .orElse("");
                        setText(text);
                    } catch (HardinessZoneNotSetException | IOException e) {
                        LOG.log(Level.WARNING, "Could not get plant for Cell", e);
                    }
                }
            }
        });
    }

    /**
     * set CallFactory for the given Tasks
     */
    private void setCellFactoryTaskListView() {
        week_listView.setCellFactory(param -> new ListCell<>() {
            @Override
            protected void updateItem(List<Task> taskList, boolean empty) {
                super.updateItem(taskList, empty);

                if (empty || taskList == null) {
                    setText(null);
                    setGraphic(null);
                } else {
                    setText("");
                    setGraphic(weekTaskVBox(taskList, this.getIndex()));
                }
            }
        });
    }

    /**
     * update task list
     * @throws IOException exception
     */
    private void loadTaskList() throws IOException {
        List<List<Task>> taskLists;
        if (selectedCrop != null) {
            gardenSchedule.getTasksUpcomingWeekForCrop(selectedCrop.getCropId().get());
        } else {
            gardenSchedule.getTasksUpcomingWeek();
        }
    }

    /**
     * Create a {@link VBox} of the given TaskList.
     * @param tasks List of {@link Task}s
     * @param dayIndex index of the day
     * @return {@link VBox} of the given Task of the day
     */
    private VBox weekTaskVBox(List<Task> tasks, int dayIndex) {
        VBox vBox = new VBox(10);
        LocalDate today = LocalDate.now();
        Label weekDay = new Label(today.plusDays(dayIndex).getDayOfWeek().toString());
        weekDay.setStyle("-fx-font-weight: bold; -fx-underline: true");
        vBox.getChildren().add(weekDay);
        for (Task task : tasks) {
            HBox hBox = new HBox(10);
            Label taskName = new Label(task.getName() + ":");
            taskName.setStyle("-fx-font-weight: bold");
            taskName.setMinWidth(100);
            taskName.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
            hBox.getChildren().addAll(taskName);

            HBox hBoxDescription = new HBox();
            Label taskDescription = new Label(task.getDescription());
            taskDescription.setWrapText(true);
            taskDescription.setMaxSize(600, Double.MAX_VALUE);
            Pane puffer = new Pane();
            HBox.setHgrow(puffer, Priority.ALWAYS);
            Button button = new Button("Task completed!");
            button.getStyleClass().add("button-class");

            button.setOnAction(new EventHandler<ActionEvent>() {
                @Override
                public void handle(ActionEvent event) {
                    showConfirmation(task);
                }
            });
            HBox.setHgrow(button, Priority.NEVER);
            hBoxDescription.getChildren().addAll(taskDescription, puffer, button);
            vBox.getChildren().addAll(hBox, hBoxDescription);
        }
        return vBox;
    }

    /**
     * Alert to confirm that task has been completed.
     * @param task {@link Task} which is selected
     */
    private void showConfirmation(Task task) {
        Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
        alert.setTitle("Task Completed?");
        alert.setHeaderText("Are you sure you have completed this task?");
        alert.setContentText("Confirming that you have completed the task will remove it from the schedule.");

        DialogPane dialogPane = alert.getDialogPane();

        dialogPane.getStylesheets().add(
                Objects.requireNonNull(getClass().getResource("bootstrap/dialogStyle.css")).toExternalForm());
        dialogPane.getStyleClass().add("myDialog");

        alert.showAndWait()
                .ifPresent(buttonType -> {
                    if (buttonType == ButtonType.OK) {
                        task.done();
                        try {
                            loadTaskList();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                });
    }

}
