package ch.zhaw.gartenverwaltung.models;

import ch.zhaw.gartenverwaltung.io.CropList;
import ch.zhaw.gartenverwaltung.io.HardinessZoneNotSetException;
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 java.io.IOException;
import java.time.LocalDate;
import java.util.List;
import java.util.Optional;


/**
 * The Gardenplan model manages the crops in the gardenplan.
 */
public class Garden {
    private final CropList cropList;
    private final ListProperty<Crop> plantedCrops = new SimpleListProperty<>(FXCollections.observableArrayList());
    private final GardenSchedule gardenSchedule;

    /**
     * Constructor of Gardenplan model
     *
     * @param gardenSchedule holds a reference to the task list object.
     */
    public Garden(GardenSchedule gardenSchedule, CropList cropList) throws IOException {
        this.gardenSchedule = gardenSchedule;
        this.cropList = cropList;
        plantedCrops.addAll(cropList.getCrops());
    }

    public ListProperty<Crop> getPlantedCrops() {
        return plantedCrops;
    }

    /**
     * Creates a Crop with a {@link Plant} and the planting date of the plant. Then let the Tasklistmodel create the
     * gardening {@link Task} for the crop. Store the crop in the gardenplan file and the cache.
     *
     * @param plant The plant which is wnated to be planted
     * @param plantingDate The date, when the plant is planted
     * @throws IOException If the database cannot be accessed
     * @throws HardinessZoneNotSetException If the hardinesszone could not be added
     * @throws PlantNotFoundException If the plant is not found in the database.
     */
    public void plantAsCrop(Plant plant, LocalDate plantingDate) throws IOException, HardinessZoneNotSetException, PlantNotFoundException {
        Crop crop = new Crop(plant.id(), plantingDate);
        //TODO Add Area to Plant
        //crop.withArea(0);
        cropList.saveCrop(crop);
        gardenSchedule.planTasksForCrop(crop);
        plantedCrops.clear();
        plantedCrops.addAll(cropList.getCrops());
    }

    /**
     * Removes a {@link Crop} from the file and the cache
     *
     * @param crop The plant which is wnated to be planted
     * @throws IOException If the database cannot be accessed
     */
    public void removeCrop(Crop crop) throws IOException {
        cropList.removeCrop(crop);
        gardenSchedule.removeTasksForCrop(crop.getCropId().orElseThrow(IllegalArgumentException::new));
        plantedCrops.clear();
        plantedCrops.addAll(cropList.getCrops());
    }

    /**
     * Updates the {@link Crop} from the file and the cache
     *
     * @param crop The crop which is being updated
     * @throws IOException If the database cannot be accessed
     */
    public void updateCrop(Crop crop) throws IOException {
        cropList.saveCrop(crop);
        plantedCrops.clear();
        plantedCrops.addAll(cropList.getCrops());
    }

    /**
     * Returns a list of {@link Crop}s which are currently in the gardenplan.
     *
     * @throws IOException If the database cannot be accessed
     */
    public List<Crop> getCrops() throws IOException {
        return cropList.getCrops();
    }

    /**
     * Returns an Optional of {@link Crop} if the crop is the gardenplan
     *
     * @param cropId The date, when the plant is planted
     * @throws IOException If the database cannot be accessed
     */
    public Optional<Crop> getCrop(Long cropId) throws IOException {
        return cropList.getCropById(cropId);
    }
}
