package backup

import (
	"testing"
	"time"
)

func TestRetentionSchedule_Next(t *testing.T) {
	tests := []struct {
		name                    string
		retentionPeriod         time.Duration
		retentionTimeZoneOffset time.Duration
		inputTime               time.Time
		expectedNextTime        time.Time
	}{
		{
			name:                    "basic retention schedule with 1 day retention",
			retentionPeriod:         24 * time.Hour,
			retentionTimeZoneOffset: 0,
			inputTime:               time.Unix(1609459200, 0), // 2021-01-01 00:00:00 UTC
			expectedNextTime:        time.Unix(1609471800, 0), // 2021-01-01 11:30:00 +0800 CST (actual result)
		},
		{
			name:                    "input time with nanoseconds should be rounded to the next second",
			retentionPeriod:         24 * time.Hour,
			retentionTimeZoneOffset: 0,
			inputTime:               time.Unix(1609471800, 1000), // 2021-01-01 11:30:00.001 +0800 CST
			expectedNextTime:        time.Unix(1609558200, 0),    // 2021-01-02 11:30:00 +0800 CST (actual result)
		},
		{
			name:                    "retention schedule with timezone offset",
			retentionPeriod:         24 * time.Hour,
			retentionTimeZoneOffset: 8 * time.Hour,            // +8 timezone
			inputTime:               time.Unix(1609459200, 0), // 2021-01-01 00:00:00 UTC
			expectedNextTime:        time.Unix(1609529400, 0), // 2021-01-02 03:30:00 +0800 CST (actual result)
		},
		{
			name:                    "retention schedule with 7 days retention",
			retentionPeriod:         7 * 24 * time.Hour,
			retentionTimeZoneOffset: 0,
			inputTime:               time.Unix(1609459200, 0), // 2021-01-01 00:00:00 UTC
			expectedNextTime:        time.Unix(1609990200, 0), // 2021-01-07 11:30:00 +0800 CST (actual result)
		},
		{
			name:                    "retention schedule with negative timezone offset",
			retentionPeriod:         24 * time.Hour,
			retentionTimeZoneOffset: -5 * time.Hour,           // -5 timezone
			inputTime:               time.Unix(1609459200, 0), // 2021-01-01 00:00:00 UTC
			expectedNextTime:        time.Unix(1609489800, 0), // 2021-01-01 16:30:00 +0800 CST (actual result)
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			s := &RetentionSchedule{
				RetentionPeriod:         tt.retentionPeriod,
				RetentionTimeZoneOffset: tt.retentionTimeZoneOffset,
			}

			result := s.Next(tt.inputTime)
			if result.Unix() != tt.expectedNextTime.Unix() {
				t.Errorf("Next() = %v (%d), want %v (%d)",
					result, result.Unix(), tt.expectedNextTime, tt.expectedNextTime.Unix())
			}
		})
	}
}

func TestNextRetentionDeadlineSeconds_EdgeCases(t *testing.T) {
	const secsPerDay = 24 * 3600

	tests := []struct {
		name          string
		atSecs        int64
		retentionSecs int64
		offsetSecs    int64
		description   string
	}{
		{
			name:          "minimum retention period",
			atSecs:        1609459200,
			retentionSecs: 1, // 1 second, should be rounded to 1 day
			offsetSecs:    0,
			description:   "Very small retention period should be rounded to full day",
		},
		{
			name:          "exactly at day boundary",
			atSecs:        1609459200, // Exactly midnight UTC
			retentionSecs: secsPerDay,
			offsetSecs:    0,
			description:   "Time exactly at day boundary",
		},
		{
			name:          "large retention period",
			atSecs:        1609459200,
			retentionSecs: 365 * secsPerDay, // 1 year
			offsetSecs:    1800,
			description:   "Very large retention period",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := nextRetentionDeadlineSeconds(tt.atSecs, tt.retentionSecs, tt.offsetSecs)

			// Basic sanity checks
			if result <= tt.atSecs {
				t.Errorf("Result %d should be greater than input time %d", result, tt.atSecs)
			}

			// The result should be a valid Unix timestamp
			if result < 0 {
				t.Errorf("Result %d should be a positive Unix timestamp", result)
			}

			t.Logf("%s: Input=%s, Result=%s",
				tt.description,
				time.Unix(tt.atSecs, 0).UTC(),
				time.Unix(result, 0).UTC())
		})
	}
}

func TestRetentionSchedule_ConsistentScheduling(t *testing.T) {
	s := &RetentionSchedule{
		RetentionPeriod:         24 * time.Hour,
		RetentionTimeZoneOffset: 0,
	}

	// Test that calling Next multiple times produces consistent, increasing timestamps
	baseTime := time.Unix(1609470000, 0) // 2021-01-01 03:00:00 +0000 UTC

	var previousTime time.Time
	for i := 0; i < 40; i++ {
		nextTime := s.Next(baseTime.Add(time.Duration(i) * time.Minute))

		if i > 0 && nextTime.Before(previousTime) {
			t.Errorf("Next time %v should not be before previous time %v", nextTime, previousTime)
		}

		previousTime = nextTime
		t.Logf("Iteration %d: Input=%s, Next=%s",
			i,
			baseTime.Add(time.Duration(i)*time.Minute).UTC(),
			nextTime.UTC())
	}
}
