package com.smppw.common.rollrange;

import com.smppw.common.pojo.dto.DateRange;
import com.smppw.common.pojo.enums.Frequency;
import com.smppw.common.rollrange.date.DateConvertorImpl;
import com.smppw.common.rollrange.date.DateVerifier;
import org.joda.time.DateTime;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author zhengsongliang
 */
public class RollingSpliter implements DateSpliter {
    private String startDate;
    private String endDate;
    private Integer rollingWindow;
    private Integer rollingStep;
    private boolean ifEdgeNeeded;
    private Frequency freq;

    public RollingSpliter(String startDate, String endDate, Integer rollingWindow, Integer rollingStep,
                          boolean ifEdgeNeeded, Frequency freq) {
        super();
        this.endDate = endDate;
        this.startDate = startDate;
        this.rollingWindow = rollingWindow;
        this.rollingStep = rollingStep;
        this.ifEdgeNeeded = ifEdgeNeeded;
        this.freq = freq;
    }

    @Override
    public List<DateRange> split() {
        List<DateRange> ranges = new ArrayList<>();

        if (rollingWindow == 0 || rollingStep == 0) {
            ranges.add(new DateRange(startDate, endDate));
            return ranges;
        }

        DateTime dtEnd = DateTime.parse(endDate);
        DateTime dtStart = DateTime.parse(startDate);

        if (Frequency.Weekly == this.freq) {
            DateTime dtWeekEnd = dtStart.plusWeeks(rollingWindow).minusDays(1);
            while (!dtWeekEnd.isAfter(dtEnd)) {
                ranges.add(new DateRange(dtStart, dtWeekEnd));
                dtStart = dtStart.plusWeeks(rollingStep);
                dtWeekEnd = dtStart.plusWeeks(rollingWindow).minusDays(1);
            }
        } else {
            DateTime dtMonthEnd = dtStart.plusMonths(rollingWindow).minusDays(1);
            while (!dtMonthEnd.isAfter(dtEnd)) {
                ranges.add(new DateRange(dtStart, dtMonthEnd));
                dtStart = dtStart.plusMonths(rollingStep);
                dtMonthEnd = dtStart.plusMonths(rollingWindow).minusDays(1);
            }
        }


        if (ifEdgeNeeded && dtStart.isBefore(dtEnd))
            ranges.add(new DateRange(dtStart, dtEnd));

        if (freq != Frequency.Daily && freq != Frequency.Weekly) {
            // Rolling Annually, when the last period is less than a full year, also should be added

//			int n = ranges.size();
//			for (int i = 0; i < n; i++) {
//				DateRange dr = ranges.get(i);
//				String start = DateVerifier.verifyPeriodStart(dr.getStartDate(), freq);
//				String end = DateVerifier.verifyPeriodEnd(dr.getEndDate(), freq);
//				dr.setStartDate(start);
//				dr.setEndDate(end);
//			}


            List<DateRange> validRanges = new ArrayList<>();
            for (DateRange dr : ranges) {
                if (DateTime.parse(dr.getStartDate()).isBefore(DateTime.parse(dr.getEndDate())))
                    validRanges.add(dr);
            }
            ranges = validRanges;
        }
        return ranges;
    }

    public static List<DateRange> getDateRangesAmong(String startDate, String endDate, Frequency rollingFrequency,
                                                     boolean ifEdgeNeeded, Frequency freq) {
        return getDateRangesAmong(startDate, endDate, rollingFrequency, ifEdgeNeeded, freq, true);
    }

    public static List<DateRange> getDateRangesAmong(String startDate, String endDate, Frequency rollingFrequency,
                                                     boolean ifEdgeNeeded, Frequency freq, boolean headEgde) {
        Frequency rollingfreq = Frequency.valueOf(rollingFrequency.name());
        DateRange drEdgeHead = null;
        String verifiedStartDate = DateVerifier.verifyPeriodStart(startDate, rollingfreq);
        if (ifEdgeNeeded) {
            String currentFreqEnd = new DateConvertorImpl().setPeriodLast(startDate, rollingfreq);
            if (!startDate.equals(verifiedStartDate)) {
                if (DateTime.parse(currentFreqEnd).isBefore(DateTime.parse(endDate)))
                    drEdgeHead = new DateRange(startDate, currentFreqEnd);
                else {
                    drEdgeHead = new DateRange(startDate, endDate);
                    return Arrays.asList(drEdgeHead);
                }
            }
        }

        if (Frequency.Weekly == rollingfreq) {
            int weekCount = 52 / (int) rollingfreq.getNum();
            //List<DateRange> ranges = new RollingSpliter(verifiedStartDate, endDate, weekCount, weekCount, ifEdgeNeeded, freq).split();
            List<DateRange> ranges = new RollingSpliter(verifiedStartDate, endDate, weekCount, weekCount, ifEdgeNeeded, rollingfreq).split();
            if (drEdgeHead != null && headEgde)
                ranges.add(0, drEdgeHead);
            return ranges;

        } else {
            int freqMonthCount = 12 / (int) rollingfreq.getNum();
            //List<DateRange> ranges = new RollingSpliter(verifiedStartDate, endDate, freqMonthCount, freqMonthCount, ifEdgeNeeded, freq).split();
            List<DateRange> ranges = new RollingSpliter(verifiedStartDate, endDate, freqMonthCount, freqMonthCount, ifEdgeNeeded, rollingfreq).split();
            if (drEdgeHead != null && headEgde)
                ranges.add(0, drEdgeHead);
            return ranges;
        }
    }

//	public static void main(String[] args) {
//		Frequency rollingfreq = Frequency.Weekly;
//		String startDate = "2020-01-01";
//		String endDate = "2020-12-22";
//		
//		String verifiedStartDate = DateVerifier.verifyPeriodStart(startDate, rollingfreq);
//
//		System.out.println(verifiedStartDate);
//
//		int weekCount = 52 / (int) rollingfreq.getNum();
//
//		System.out.println("week:" + weekCount);
//
//		List<DateRange> ranges = new RollingSpliter(verifiedStartDate, endDate, weekCount, weekCount, true, rollingfreq).split();
//
//		for (DateRange dr : ranges)
//			System.out.println(dr);
//		
//	}
}
