package actionssummerwindnet

import (
	"testing"
	"time"
)

func TestCalculateActiveAndUpcomingRecurringPeriods(t *testing.T) {
	type recurrence struct {
		Start string
		End   string
		Freq  string
		Until string
	}

	type testcase struct {
		now string

		recurrence recurrence

		wantActive   string
		wantUpcoming string
	}

	check := func(t *testing.T, tc testcase) {
		t.Helper()

		_, err := time.Parse(time.RFC3339, "2021-05-08T00:00:00Z")
		if err != nil {
			t.Fatal(err)
		}

		now, err := time.Parse(time.RFC3339, tc.now)
		if err != nil {
			t.Fatal(err)
		}

		active, upcoming, err := parseAndMatchRecurringPeriod(now, tc.recurrence.Start, tc.recurrence.End, tc.recurrence.Freq, tc.recurrence.Until)
		if err != nil {
			t.Fatal(err)
		}

		if active.String() != tc.wantActive {
			t.Errorf("unexpected active: want %q, got %q", tc.wantActive, active)
		}

		if upcoming.String() != tc.wantUpcoming {
			t.Errorf("unexpected upcoming: want %q, got %q", tc.wantUpcoming, upcoming)
		}
	}

	t.Run("onetime override about to start", func(t *testing.T) {
		t.Helper()

		check(t, testcase{
			recurrence: recurrence{
				Start: "2021-05-01T00:00:00+09:00",
				End:   "2021-05-03T00:00:00+09:00",
			},

			now: "2021-04-30T23:59:59+09:00",

			wantActive:   "",
			wantUpcoming: "2021-05-01T00:00:00+09:00-2021-05-03T00:00:00+09:00",
		})
	})

	t.Run("onetime override started", func(t *testing.T) {
		t.Helper()

		check(t, testcase{
			recurrence: recurrence{
				Start: "2021-05-01T00:00:00+09:00",
				End:   "2021-05-03T00:00:00+09:00",
			},

			now: "2021-05-01T00:00:00+09:00",

			wantActive:   "2021-05-01T00:00:00+09:00-2021-05-03T00:00:00+09:00",
			wantUpcoming: "",
		})
	})

	t.Run("onetime override about to end", func(t *testing.T) {
		t.Helper()

		check(t, testcase{
			recurrence: recurrence{
				Start: "2021-05-01T00:00:00+09:00",
				End:   "2021-05-03T00:00:00+09:00",
			},

			now: "2021-05-02T23:59:59+09:00",

			wantActive:   "2021-05-01T00:00:00+09:00-2021-05-03T00:00:00+09:00",
			wantUpcoming: "",
		})
	})

	t.Run("onetime override ended", func(t *testing.T) {
		t.Helper()

		check(t, testcase{
			recurrence: recurrence{
				Start: "2021-05-01T00:00:00+09:00",
				End:   "2021-05-03T00:00:00+09:00",
			},

			now: "2021-05-03T00:00:00+09:00",

			wantActive:   "",
			wantUpcoming: "",
		})
	})

	t.Run("weekly override about to start", func(t *testing.T) {
		t.Helper()

		check(t, testcase{
			recurrence: recurrence{
				Start: "2021-05-01T00:00:00+09:00",
				End:   "2021-05-03T00:00:00+09:00",
				Freq:  "Weekly",
				Until: "2022-05-01T00:00:00+09:00",
			},

			now: "2021-04-30T23:59:59+09:00",

			wantActive:   "",
			wantUpcoming: "2021-05-01T00:00:00+09:00-2021-05-03T00:00:00+09:00",
		})
	})

	t.Run("weekly override started", func(t *testing.T) {
		t.Helper()

		check(t, testcase{
			recurrence: recurrence{
				Start: "2021-05-01T00:00:00+09:00",
				End:   "2021-05-03T00:00:00+09:00",
				Freq:  "Weekly",
				Until: "2022-05-01T00:00:00+09:00",
			},

			now: "2021-05-01T00:00:00+09:00",

			wantActive:   "2021-05-01T00:00:00+09:00-2021-05-03T00:00:00+09:00",
			wantUpcoming: "2021-05-08T00:00:00+09:00-2021-05-10T00:00:00+09:00",
		})
	})

	t.Run("weekly override about to end", func(t *testing.T) {
		t.Helper()

		check(t, testcase{
			recurrence: recurrence{
				Start: "2021-05-01T00:00:00+09:00",
				End:   "2021-05-03T00:00:00+09:00",
				Freq:  "Weekly",
				Until: "2022-05-01T00:00:00+09:00",
			},

			now: "2021-05-02T23:59:59+09:00",

			wantActive:   "2021-05-01T00:00:00+09:00-2021-05-03T00:00:00+09:00",
			wantUpcoming: "2021-05-08T00:00:00+09:00-2021-05-10T00:00:00+09:00",
		})
	})

	t.Run("weekly override ended", func(t *testing.T) {
		t.Helper()

		check(t, testcase{
			recurrence: recurrence{
				Start: "2021-05-01T00:00:00+09:00",
				End:   "2021-05-03T00:00:00+09:00",
				Freq:  "Weekly",
				Until: "2022-05-01T00:00:00+09:00",
			},

			now: "2021-05-03T00:00:00+09:00",

			wantActive:   "",
			wantUpcoming: "2021-05-08T00:00:00+09:00-2021-05-10T00:00:00+09:00",
		})
	})

	t.Run("weekly override reccurrence about to start", func(t *testing.T) {
		t.Helper()

		check(t, testcase{
			recurrence: recurrence{
				Start: "2021-05-01T00:00:00+09:00",
				End:   "2021-05-03T00:00:00+09:00",
				Freq:  "Weekly",
				Until: "2022-05-01T00:00:00+09:00",
			},

			now: "2021-05-07T23:59:59+09:00",

			wantActive:   "",
			wantUpcoming: "2021-05-08T00:00:00+09:00-2021-05-10T00:00:00+09:00",
		})
	})

	t.Run("weekly override reccurrence started", func(t *testing.T) {
		t.Helper()

		check(t, testcase{
			recurrence: recurrence{
				Start: "2021-05-01T00:00:00+09:00",
				End:   "2021-05-03T00:00:00+09:00",
				Freq:  "Weekly",
				Until: "2022-05-01T00:00:00+09:00",
			},

			now: "2021-05-08T00:00:00+09:00",

			wantActive:   "2021-05-08T00:00:00+09:00-2021-05-10T00:00:00+09:00",
			wantUpcoming: "2021-05-15T00:00:00+09:00-2021-05-17T00:00:00+09:00",
		})
	})

	t.Run("weekly override reccurrence about to end", func(t *testing.T) {
		t.Helper()

		check(t, testcase{
			recurrence: recurrence{
				Start: "2021-05-01T00:00:00+09:00",
				End:   "2021-05-03T00:00:00+09:00",
				Freq:  "Weekly",
				Until: "2022-05-01T00:00:00+09:00",
			},

			now: "2021-05-09T23:59:59+09:00",

			wantActive:   "2021-05-08T00:00:00+09:00-2021-05-10T00:00:00+09:00",
			wantUpcoming: "2021-05-15T00:00:00+09:00-2021-05-17T00:00:00+09:00",
		})
	})

	t.Run("weekly override reccurrence ended", func(t *testing.T) {
		t.Helper()

		check(t, testcase{
			recurrence: recurrence{
				Start: "2021-05-01T00:00:00+09:00",
				End:   "2021-05-03T00:00:00+09:00",
				Freq:  "Weekly",
				Until: "2022-05-01T00:00:00+09:00",
			},

			now: "2021-05-10T00:00:00+09:00",

			wantActive:   "",
			wantUpcoming: "2021-05-15T00:00:00+09:00-2021-05-17T00:00:00+09:00",
		})
	})

	t.Run("weekly override's last reccurrence about to start", func(t *testing.T) {
		t.Helper()

		check(t, testcase{
			recurrence: recurrence{
				Start: "2021-05-01T00:00:00+09:00",
				End:   "2021-05-03T00:00:00+09:00",
				Freq:  "Weekly",
				Until: "2022-05-01T00:00:00+09:00",
			},

			now: "2022-04-29T23:59:59+09:00",

			wantActive:   "",
			wantUpcoming: "2022-04-30T00:00:00+09:00-2022-05-02T00:00:00+09:00",
		})
	})

	t.Run("weekly override reccurrence started", func(t *testing.T) {
		t.Helper()

		check(t, testcase{
			recurrence: recurrence{
				Start: "2021-05-01T00:00:00+09:00",
				End:   "2021-05-03T00:00:00+09:00",
				Freq:  "Weekly",
				Until: "2022-05-01T00:00:00+09:00",
			},

			now: "2022-04-30T00:00:00+09:00",

			wantActive:   "2022-04-30T00:00:00+09:00-2022-05-02T00:00:00+09:00",
			wantUpcoming: "",
		})
	})

	t.Run("weekly override reccurrence about to end", func(t *testing.T) {
		t.Helper()

		check(t, testcase{
			recurrence: recurrence{
				Start: "2021-05-01T00:00:00+09:00",
				End:   "2021-05-03T00:00:00+09:00",
				Freq:  "Weekly",
				Until: "2022-05-01T00:00:00+09:00",
			},

			now: "2022-05-01T23:59:59+09:00",

			wantActive:   "2022-04-30T00:00:00+09:00-2022-05-02T00:00:00+09:00",
			wantUpcoming: "",
		})
	})

	t.Run("weekly override reccurrence ended", func(t *testing.T) {
		t.Helper()

		check(t, testcase{
			recurrence: recurrence{
				Start: "2021-05-01T00:00:00+09:00",
				End:   "2021-05-03T00:00:00+09:00",
				Freq:  "Weekly",
				Until: "2022-05-01T00:00:00+09:00",
			},

			now: "2022-05-02T00:00:00+09:00",

			wantActive:   "",
			wantUpcoming: "",
		})
	})

	t.Run("weekly override repeated forever started", func(t *testing.T) {
		t.Helper()

		check(t, testcase{
			recurrence: recurrence{
				Start: "2021-05-01T00:00:00+09:00",
				End:   "2021-05-03T00:00:00+09:00",
				Freq:  "Weekly",
			},

			now: "2021-05-08T00:00:00+09:00",

			wantActive:   "2021-05-08T00:00:00+09:00-2021-05-10T00:00:00+09:00",
			wantUpcoming: "2021-05-15T00:00:00+09:00-2021-05-17T00:00:00+09:00",
		})
	})

	t.Run("monthly override started", func(t *testing.T) {
		t.Helper()

		check(t, testcase{
			recurrence: recurrence{
				Start: "2021-05-01T00:00:00+09:00",
				End:   "2021-05-03T00:00:00+09:00",
				Freq:  "Monthly",
				Until: "2022-05-01T00:00:00+09:00",
			},

			now: "2021-05-01T00:00:00+09:00",

			wantActive:   "2021-05-01T00:00:00+09:00-2021-05-03T00:00:00+09:00",
			wantUpcoming: "2021-06-01T00:00:00+09:00-2021-06-03T00:00:00+09:00",
		})
	})

	t.Run("monthly override recurrence started", func(t *testing.T) {
		t.Helper()

		check(t, testcase{
			recurrence: recurrence{
				Start: "2021-05-01T00:00:00+09:00",
				End:   "2021-05-03T00:00:00+09:00",
				Freq:  "Monthly",
				Until: "2022-05-01T00:00:00+09:00",
			},

			now: "2021-06-01T00:00:00+09:00",

			wantActive:   "2021-06-01T00:00:00+09:00-2021-06-03T00:00:00+09:00",
			wantUpcoming: "2021-07-01T00:00:00+09:00-2021-07-03T00:00:00+09:00",
		})
	})

	t.Run("monthly override's last reccurence about to start", func(t *testing.T) {
		t.Helper()

		check(t, testcase{
			recurrence: recurrence{
				Start: "2021-05-01T00:00:00+09:00",
				End:   "2021-05-03T00:00:00+09:00",
				Freq:  "Monthly",
				Until: "2022-05-01T00:00:00+09:00",
			},

			now: "2022-04-30T23:59:59+09:00",

			wantActive:   "",
			wantUpcoming: "2022-05-01T00:00:00+09:00-2022-05-03T00:00:00+09:00",
		})
	})

	t.Run("monthly override's last reccurence started", func(t *testing.T) {
		t.Helper()

		check(t, testcase{
			recurrence: recurrence{
				Start: "2021-05-01T00:00:00+09:00",
				End:   "2021-05-03T00:00:00+09:00",
				Freq:  "Monthly",
				Until: "2022-05-01T00:00:00+09:00",
			},

			now: "2022-05-01T00:00:00+09:00",

			wantActive:   "2022-05-01T00:00:00+09:00-2022-05-03T00:00:00+09:00",
			wantUpcoming: "",
		})
	})

	t.Run("monthly override's last reccurence started", func(t *testing.T) {
		t.Helper()

		check(t, testcase{
			recurrence: recurrence{
				Start: "2021-05-01T00:00:00+09:00",
				End:   "2021-05-03T00:00:00+09:00",
				Freq:  "Monthly",
				Until: "2022-05-01T00:00:00+09:00",
			},

			now: "2022-05-01T00:00:01+09:00",

			wantActive:   "2022-05-01T00:00:00+09:00-2022-05-03T00:00:00+09:00",
			wantUpcoming: "",
		})
	})

	t.Run("monthly override's last reccurence ending", func(t *testing.T) {
		t.Helper()

		check(t, testcase{
			recurrence: recurrence{
				Start: "2021-05-01T00:00:00+09:00",
				End:   "2021-05-03T00:00:00+09:00",
				Freq:  "Monthly",
				Until: "2022-05-01T00:00:00+09:00",
			},

			now: "2022-05-02T23:59:59+09:00",

			wantActive:   "2022-05-01T00:00:00+09:00-2022-05-03T00:00:00+09:00",
			wantUpcoming: "",
		})
	})

	t.Run("monthly override's last reccurence ended", func(t *testing.T) {
		t.Helper()

		check(t, testcase{
			recurrence: recurrence{
				Start: "2021-05-01T00:00:00+09:00",
				End:   "2021-05-03T00:00:00+09:00",
				Freq:  "Monthly",
				Until: "2022-05-01T00:00:00+09:00",
			},

			now: "2022-05-03T00:00:00+09:00",

			wantActive:   "",
			wantUpcoming: "",
		})
	})

	t.Run("yearly override started", func(t *testing.T) {
		t.Helper()

		check(t, testcase{
			recurrence: recurrence{
				Start: "2021-05-01T00:00:00+09:00",
				End:   "2021-05-03T00:00:00+09:00",
				Freq:  "Yearly",
				Until: "2022-05-01T00:00:00+09:00",
			},

			now: "2021-05-01T00:00:00+09:00",

			wantActive:   "2021-05-01T00:00:00+09:00-2021-05-03T00:00:00+09:00",
			wantUpcoming: "2022-05-01T00:00:00+09:00-2022-05-03T00:00:00+09:00",
		})
	})

	t.Run("yearly override reccurrence started", func(t *testing.T) {
		t.Helper()

		check(t, testcase{
			recurrence: recurrence{
				Start: "2021-05-01T00:00:00+09:00",
				End:   "2021-05-03T00:00:00+09:00",
				Freq:  "Yearly",
				Until: "2023-05-01T00:00:00+09:00",
			},

			now: "2022-05-01T00:00:00+09:00",

			wantActive:   "2022-05-01T00:00:00+09:00-2022-05-03T00:00:00+09:00",
			wantUpcoming: "2023-05-01T00:00:00+09:00-2023-05-03T00:00:00+09:00",
		})
	})

	t.Run("yearly override's last recurrence about to start", func(t *testing.T) {
		t.Helper()

		check(t, testcase{
			recurrence: recurrence{
				Start: "2021-05-01T00:00:00+09:00",
				End:   "2021-05-03T00:00:00+09:00",
				Freq:  "Yearly",
				Until: "2023-05-01T00:00:00+09:00",
			},

			now: "2023-04-30T23:59:59+09:00",

			wantActive:   "",
			wantUpcoming: "2023-05-01T00:00:00+09:00-2023-05-03T00:00:00+09:00",
		})
	})

	t.Run("yearly override's last recurrence started", func(t *testing.T) {
		t.Helper()

		check(t, testcase{
			recurrence: recurrence{
				Start: "2021-05-01T00:00:00+09:00",
				End:   "2021-05-03T00:00:00+09:00",
				Freq:  "Yearly",
				Until: "2023-05-01T00:00:00+09:00",
			},

			now: "2023-05-01T00:00:00+09:00",

			wantActive:   "2023-05-01T00:00:00+09:00-2023-05-03T00:00:00+09:00",
			wantUpcoming: "",
		})
	})

	t.Run("yearly override's last recurrence ending", func(t *testing.T) {
		t.Helper()

		check(t, testcase{
			recurrence: recurrence{
				Start: "2021-05-01T00:00:00+09:00",
				End:   "2021-05-03T00:00:00+09:00",
				Freq:  "Yearly",
				Until: "2023-05-01T00:00:00+09:00",
			},

			now: "2023-05-02T23:23:59+09:00",

			wantActive:   "2023-05-01T00:00:00+09:00-2023-05-03T00:00:00+09:00",
			wantUpcoming: "",
		})
	})

	t.Run("yearly override's last recurrence ended", func(t *testing.T) {
		t.Helper()

		check(t, testcase{
			recurrence: recurrence{
				Start: "2021-05-01T00:00:00+09:00",
				End:   "2021-05-03T00:00:00+09:00",
				Freq:  "Yearly",
				Until: "2023-05-01T00:00:00+09:00",
			},

			now: "2023-05-03T00:00:00+09:00",

			wantActive:   "",
			wantUpcoming: "",
		})
	})
}

func parseAndMatchRecurringPeriod(now time.Time, start, end, frequency, until string) (*Period, *Period, error) {
	startTime, err := time.Parse(time.RFC3339, start)
	if err != nil {
		return nil, nil, err
	}

	endTime, err := time.Parse(time.RFC3339, end)
	if err != nil {
		return nil, nil, err
	}

	var untilTime time.Time

	if until != "" {
		ut, err := time.Parse(time.RFC3339, until)
		if err != nil {
			return nil, nil, err
		}

		untilTime = ut
	}

	return MatchSchedule(now, startTime, endTime, RecurrenceRule{Frequency: frequency, UntilTime: untilTime})
}

func FuzzMatchSchedule(f *testing.F) {
	start := time.Now()
	end := time.Now()
	now := time.Now()
	f.Fuzz(func(t *testing.T, freq string) {
		// Verify that it never panics
		_, _, _ = MatchSchedule(now, start, end, RecurrenceRule{Frequency: freq})
	})
}
