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.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.beans.property.ListProperty;
import javafx.beans.property.SimpleListProperty;
import javafx.collections.FXCollections;
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.logging.Level;
import java.util.logging.Logger;

public class MyScheduleController {
    private static final Logger LOG = Logger.getLogger(MyScheduleController.class.getName());
    private final ListProperty<List<Task>> taskListProperty = new SimpleListProperty<>(FXCollections.observableArrayList());

    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;

    @AfterInject
    @SuppressWarnings("unused")
    public void init() {
        setCellFactoryCropListView();
        setCellFactoryTaskListView();
        scheduledPlants_listview.itemsProperty().bind(garden.getPlantedCrops());
        week_listView.itemsProperty().bind(taskListProperty);
        lookForSelectedListEntries();
        information_label.setText("");
        try {
            loadTaskList();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void lookForSelectedListEntries() {
        scheduledPlants_listview.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
            selectedCrop = newValue;
            try {
                loadTaskList();
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
    }

    private void setCellFactoryCropListView() {
        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);
                    }
                }
            }
        });
    }

    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) {
                    setGraphic(null);
                    setText(null);
                } else {
                    setText("");
                    setGraphic(weekTaskVBox(taskList, this.getIndex()));
                }
            }
        });
    }

    private void loadTaskList() throws IOException {
        List<List<Task>> taskLists;
        if (selectedCrop != null) {
            taskLists = gardenSchedule.getTasksUpcomingWeekForCrop(selectedCrop.getCropId().get());
        } else {
            taskLists = gardenSchedule.getTasksUpcomingWeek();
        }
        taskListProperty.clear();
        taskListProperty.addAll(taskLists);
    }

    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);
            CheckBox checkBox = new CheckBox("Task completed?");
            checkBox.selectedProperty().addListener((observable, oldValue, newValue) -> {
                if (newValue) {
                    showConfirmation(task, checkBox);
                }
            });
            HBox.setHgrow(checkBox, Priority.NEVER);
            hBoxDescription.getChildren().addAll(taskDescription, puffer, checkBox);
            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, CheckBox checkBox) {
        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.");

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


}
