package ch.zhaw.gartenverwaltung;

import ch.zhaw.gartenverwaltung.bootstrap.AppLoader;
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.models.PlantNotFoundException;
import ch.zhaw.gartenverwaltung.types.Crop;
import ch.zhaw.gartenverwaltung.types.Pest;
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.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.geometry.Pos;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.stage.Stage;

import java.io.IOException;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

public class CropDetailController {
    private Crop crop;

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

    @Inject
    AppLoader appLoader;

    private static final Logger LOG = Logger.getLogger(CropDetailController.class.getName());
    private final ListProperty<Task> taskListProperty = new SimpleListProperty<>(FXCollections.observableArrayList());
    private final ListProperty<Pest> pestListProperty = new SimpleListProperty<>(FXCollections.observableArrayList());

    @FXML
    private ImageView imageView;

    @FXML
    private Button area_button;

    @FXML
    private Label area_label;

    @FXML
    private Label cropName_label;

    @FXML
    private Label description_label;

    @FXML
    private Label location_label;

    @FXML
    private Label light_label;

    @FXML
    private Button location_button;

    @FXML
    private Label soil_label;

    @FXML
    private Label spacing_label;

    @FXML
    private Button addTask_button;

    @FXML
    private ListView<Task> taskList_listView;

    @FXML
    private ListView<Pest> pests_listView;

    @FXML
    void addTask() throws IOException {
        createTaskDialog(true, null);
    }

    /**
     * close Window
     */
    @FXML
    void goBack() {
        Stage stage = (Stage) imageView.getScene().getWindow();
        stage.close();
    }

    /**
     * open dialog to set area
     */
    @FXML
    void setArea() {

    }

    /**
     * open dialog to set location
     */
    @FXML
    void setLocation() {

    }

    /**
     * set labels and image from selected {@link Crop}
     * set icons for buttons
     * @param crop {@link Crop} which will be displayed
     * @throws PlantNotFoundException exception
     */
    public void setPlantFromCrop(Crop crop) throws PlantNotFoundException {
        this.crop = crop;
        try {
            Plant plant = plantList.getPlantById(Settings.getInstance().getCurrentHardinessZone(), crop.getPlantId())
                    .orElseThrow(PlantNotFoundException::new);

            cropName_label.setText(plant.name());
            description_label.setText(plant.description());
            light_label.setText(String.valueOf(plant.light()));
            soil_label.setText(plant.soil());
            spacing_label.setText(plant.spacing());
            if (plant.image() != null) {
                imageView.setImage(plant.image());
            }
            area_label.setText("");
            location_label.setText("");

            setTaskListProperty(crop);
            taskList_listView.itemsProperty().bind(taskListProperty);

            pestListProperty.addAll(plant.pests());
            pests_listView.itemsProperty().bind(pestListProperty);


        } catch (HardinessZoneNotSetException | IOException e) {
            throw new PlantNotFoundException();
        }
        setIconToButton(addTask_button, "addIcon.png");
        setIconToButton(area_button, "areaIcon.png");
        setIconToButton(location_button, "locationIcon.png");
        setCellFactoryPests();
        setCellFactoryTasks();
    }

    private void setCellFactoryTasks() {
        taskList_listView.setCellFactory(param -> new ListCell<>() {
            @Override
            protected void updateItem(Task task, boolean empty) {
                super.updateItem(task, empty);

                if (empty || task == null) {
                    setText(null);
                    setGraphic(null);
                } else {
                    setText("");
                    setGraphic(createTaskHBox(task));
                }
            }
        });
    }

    private void setCellFactoryPests() {
        pests_listView.setCellFactory(param -> new ListCell<>() {
            @Override
            protected void updateItem(Pest pest, boolean empty) {
                super.updateItem(pest, empty);

                if (empty || pest == null) {
                    setText(null);
                    setGraphic(null);
                } else {
                    setText("");
                    setGraphic(createPestHBox(pest));
                }
            }
        });
    }

    private void setTaskListProperty(Crop crop) {
        crop.getCropId().ifPresent(id -> {
            List<Task> taskList;
            try {
                taskList = gardenSchedule.getTaskListForCrop(id);
                taskListProperty.clear();
                taskListProperty.addAll(taskList);
            } catch (IOException e) {
                // TODO: Alert
                LOG.log(Level.SEVERE, "Could not get task list for crop", e.getCause());
            }
        });
    }

    private HBox createTaskHBox(Task task) {
        HBox hBox = new HBox();
        Label taskName = new Label(task.getName()+": ");
        taskName.setStyle("-fx-font-weight: bold");
        Label taskDescription = new Label(task.getDescription());
        taskDescription.setWrapText(true);
        taskDescription.setMaxWidth(2000);
        HBox.setHgrow(taskDescription, Priority.ALWAYS);

        Button edit = new Button();
        Button delete = new Button();
        setIconToButton(edit, "editIcon.png");
        setIconToButton(delete, "deleteIcon.png");
        edit.setOnAction(getEditTaskEvent(task));

        hBox.getChildren().addAll(taskName, taskDescription, edit, delete);
        return hBox;
    }

    private HBox createPestHBox(Pest pest) {
        Label label = new Label(pest.name() + ":    ");
        label.setStyle("-fx-font-weight: bold");
        HBox hBox = new HBox();
        hBox.fillHeightProperty();
        Label label1 = new Label(pest.description());
        label1.setAlignment(Pos.TOP_LEFT);
        label1.setWrapText(true);
        label1.setMaxWidth(600);
        Button button = new Button("Get Counter Measures");
        hBox.getChildren().addAll(label, label1, button);
        return hBox;
    }

    /**
     * adds icon to button
     * @param button the button which get the icon
     * @param iconFileName file name of icon
     */
    private void setIconToButton(Button button, String iconFileName) {
        Image img = new Image(String.valueOf(getClass().getResource("icons/" + iconFileName)));
        ImageView imageView = new ImageView(img);
        imageView.setFitHeight(20);
        imageView.setPreserveRatio(true);
        button.setGraphic(imageView);
    }

    private EventHandler<ActionEvent> getEditTaskEvent(Task task) {
        return (event) -> {
            try {
                createTaskDialog(false, task);
            } catch (IOException e) {
                e.printStackTrace();
            }
        };
    }

    private void createTaskDialog(boolean newTask, Task givenTask) throws IOException {
        Dialog<Task> dialog = new Dialog<>();
        dialog.setTitle("Set Task");
        dialog.setHeaderText("Add/Edit Task:");
        dialog.setResizable(false);

        DialogPane dialogPane = dialog.getDialogPane();

        ButtonType saveTask;
        if(newTask) {
            saveTask = new ButtonType("Add", ButtonBar.ButtonData.OK_DONE);
        } else {
            saveTask = new ButtonType("Save", ButtonBar.ButtonData.OK_DONE);
        }
        dialogPane.getButtonTypes().addAll(saveTask, ButtonType.CANCEL);

        if (appLoader.loadPaneToDialog("TaskFormular.fxml", dialogPane) instanceof TaskFormularController controller) {
            controller.setCorp(this.crop);
            if (!newTask) {
                controller.setTaskValue(givenTask);
            }
            dialog.setResultConverter(button -> button.equals(saveTask) ? controller.returnResult() : null);

            dialog.showAndWait()
                    .ifPresent(task -> {
                        if (newTask) {
                            try {
                                gardenSchedule.addTask(task);
                                setTaskListProperty(this.crop);
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        } else {
                            //ToDo method to edit task
                            setTaskListProperty(this.crop);
                        }
                    });
        }

    }
}
