package ch.zhaw.gartenverwaltung.types;

import javafx.scene.image.Image;

import java.time.LocalDate;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

import static java.time.temporal.ChronoUnit.DAYS;

public record Plant(
        long id,
        String name,
        String description,
        Image image,
        String spacing,
        int light,
        String soil,
        List<Pest> pests,
        List<GrowthPhase> lifecycle) {

    /**
     * remove all growthPhase which do not belong to the hardiness zone
     * @param zone hardiness zone
     */
    public void inZone(HardinessZone zone) {
        lifecycle.removeIf(growthPhase -> !growthPhase.zone().equals(zone));
    }

    /**
     * get all growthPhases of lifecycle group
     * @param group lifecycle group
     * @return list of growthPhases
     */
    public List<GrowthPhase> lifecycleForGroup(int group) {
        return lifecycle.stream()
                .filter(growthPhase -> growthPhase.group() == group)
                .collect(Collectors.toList());
    }

    /**
     * get sow date from given harvest day from lifecycle group
     * @param harvestDate date of the harvest
     * @param group lifecycle group
     * @return LocaleDate of sow date
     */
    public LocalDate sowDateFromHarvestDate(LocalDate harvestDate, int group) {
        return harvestDate.minusDays(timeToHarvest(group));
    }

    /**
     * calculate the days between sow and harvest day for lifecycle group
     * @param group the lifecycle group
     * @return Integer number of dates between sow and harvest day
     */
    public int timeToHarvest(int group) {
        List<GrowthPhase> activeLifecycle = lifecycleForGroup(group);
        GrowthPhase sow = activeLifecycle.stream()
                .filter(growthPhase -> !growthPhase.type().equals(GrowthPhaseType.SOW))
                .findFirst()
                .orElseThrow();
        GrowthPhase harvest = activeLifecycle.stream()
                .filter(growthPhase -> !growthPhase.type().equals(GrowthPhaseType.HARVEST))
                .findFirst()
                .orElseThrow();

        int currentYear = LocalDate.now().getYear();
        return (int) DAYS.between(harvest.startDate().atYear(currentYear), sow.startDate().atYear(currentYear));
    }

    /**
     * filter out the given growthPhase out of the lifecycle
     * create list of dates for this growthPhase and return it
     * @param growthPhase the wanted growthPhase
     * @return a list of dates of the current year
     */
    public List<LocalDate> getDateListOfGrowthPhase(GrowthPhaseType growthPhase) {
        List<LocalDate> dates = new LinkedList<>();
        for (GrowthPhase growth : lifecycle) {
            if (growth.type().equals(growthPhase)) {
                dates = addDatesFromMonthDay(growth);
            }
        }
        return dates;
    }

    /**
     * transform monthDay value of the given growthPhase to localDate
     * return a list of dates from start to end of growth phase
     * @param growthPhase the current growthPhase
     * @return a list of dates of the current year
     */
    private List<LocalDate> addDatesFromMonthDay(GrowthPhase growthPhase) {
        List<LocalDate> dates = new LinkedList<>();
        LocalDate today = LocalDate.now();
        LocalDate start = growthPhase.startDate().atYear(today.getYear());
        LocalDate end = growthPhase.endDate().atYear(today.getYear());
        while (!start.isAfter(end)) {
            dates.add(start);
            start = start.plusDays(1);
        }
        return dates;
    }
}
