package ch.zhaw.gartenverwaltung;

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

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

/**
 * Controller class for the MyGarden.fxml file
 */
public class MyGardenController {
    private static final Logger LOG = Logger.getLogger(MyGardenController.class.getName());
    @Inject
    AppLoader appLoader;
    @Inject
    private Garden garden;
    @Inject
    private PlantList plantList;

    @FXML
    public AnchorPane myGardenRoot;
    @FXML
    private Button addPlant_button;
    @FXML
    private ListView<Crop> myGarden_listView;

    /**
     * initialize crop list
     * add listener for crop list
     * set icon for button
     */
    @AfterInject
    @SuppressWarnings("unused")
    public void init() {
        setIconToButton(addPlant_button, "addIcon.png");
        myGarden_listView.itemsProperty().bind(garden.getPlantedCrops());
        setCellFactory();
    }

    /**
     * redirect to plant fxml file
     */
    @FXML
    void addPlant() {
        myGardenRoot.fireEvent(new ChangeViewEvent(ChangeViewEvent.CHANGE_MAIN_VIEW, "Plants.fxml"));
    }

    /**
     * set cell factory to load {@link HBox} as list view content
     */
    private void setCellFactory() {
        myGarden_listView.setCellFactory(param -> new ListCell<>() {
            @Override
            protected void updateItem(Crop crop, boolean empty) {
                super.updateItem(crop, empty);

                if (empty || crop == null) {
                    setText(null);
                    setGraphic(null);
                } else {
                    try {
                        setText("");
                        setGraphic(createHBoxForListView(crop));
                    } catch (HardinessZoneNotSetException | IOException e) {
                        LOG.log(Level.WARNING, "Could not get plant for Cell", e);
                    }
                }
            }
        });
    }

    /**
     * Creates and returns HBox of the crop
     * @param crop {@link Crop} which is selected
     * @return {@link HBox} of the {@link Crop}
     * @throws HardinessZoneNotSetException exception
     * @throws IOException exception
     */
    private HBox createHBoxForListView(Crop crop) throws HardinessZoneNotSetException, IOException {
        //ToDo add better design
        Plant plant = plantList.getPlantById(Settings.getInstance().getCurrentHardinessZone(), crop.getPlantId()).get();
        HBox hBox = new HBox(10);
        ImageView imageView = new ImageView();
        imageView.setPreserveRatio(false);
        imageView.setFitHeight(100);
        imageView.setFitWidth(100);
        imageView.maxHeight(100);
        if (plant.image() != null) {
            imageView.setImage(plant.image());
        }
        hBox.setMinHeight(100);
        Label label = new Label(plant.name());
        label.setMaxWidth(2000);
        HBox.setHgrow(label, Priority.ALWAYS);

        Button details = new Button();
        Button delete = new Button();
        details.getStyleClass().add("button-class");
        delete.getStyleClass().add("button-class");

        setIconToButton(details, "detailsIcon.png");
        setIconToButton(delete, "deleteIcon.png");
        details.setOnAction(getGoToCropDetailEvent(crop));
        delete.setOnAction(getDeleteCropEvent(crop));
        
        hBox.getChildren().addAll(imageView, label, details, delete);
        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);
    }

    /**
     * open detail window of the selected {@link Crop}
     * @param crop {@link Crop} which is selected
     * @return {@link EventHandler} for button
     */
    private EventHandler<ActionEvent> getGoToCropDetailEvent(Crop crop) {
        return (event) -> {
            try {
                Stage stage = new Stage();
                if (appLoader.loadSceneToStage("CropDetail.fxml", stage) instanceof CropDetailController controller) {
                    controller.setPlantFromCrop(crop);
                }
                stage.initModality(Modality.APPLICATION_MODAL);
                stage.setResizable(true);
                stage.showAndWait();
            } catch (IOException | PlantNotFoundException e) {
                // TODO: show error alert
                LOG.log(Level.SEVERE, "Could not load plant details.", e);
            }
        };
    }

    /**
     * open alert for deleting the selected {@link Crop}
     * @param crop {@link Crop} which is selected
     * @return {@link EventHandler} for button
     */
    private EventHandler<ActionEvent> getDeleteCropEvent(Crop crop) {
        return (event) -> {
            try {
                showConfirmation(crop);
            } catch (IOException | HardinessZoneNotSetException e) {
                e.printStackTrace();
            }
        };
    }

    /**
     * Alert to confirm that the crop can be deleted.
     * @param crop {@link Crop} which is selected
     * @throws IOException exception
     * @throws HardinessZoneNotSetException exception
     */
    private void showConfirmation(Crop crop) throws IOException, HardinessZoneNotSetException {
        Plant plant = plantList.getPlantById(Settings.getInstance().getCurrentHardinessZone(), crop.getPlantId()).get();
        Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
        alert.setTitle("Delete " + plant.name());
        DialogPane dialogPane = alert.getDialogPane();

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

        alert.setHeaderText("Are you sure want to delete this Crop?");
        alert.setContentText("Deleting this crop will remove all associated tasks from your schedule.");

        alert.showAndWait()
                .ifPresent(buttonType -> {
                    if (buttonType == ButtonType.OK) {
                        try {
                            garden.removeCrop(crop);
                        } catch (IOException e) {
                            // TODO: Show error alert
                            LOG.log(Level.SEVERE, "Could not remove crop.", e);
                        }
                    }
                });
    }
}
