package entity

import (
	"testing"
	"time"

	"github.com/stretchr/testify/require"
	"github.com/tidbcloud/serverless-service/internal/config"
)

func TestDefaultBackupPlacement(t *testing.T) {
	savedConfig := config.Global()
	config.Set(&config.CentralConfig{ServerConfig: config.ServerConfig{Stage: "staging"}})
	t.Cleanup(func() {
		config.Set(savedConfig)
	})

	history := &BackupScheduleHistory{Region: "AWS-US-EAST-1"}
	require.Equal(t, "staging-aws-us-east-1-f01", history.GetKubernetes())
	require.Equal(t, DefaultCloudProvider, history.GetCloudProvider())

	prefix, suffix := DefaultKubernetesNameParts()
	require.Equal(t, prefix+"aws-us-east-1"+suffix, history.GetKubernetes())
}

func TestBackupScheduleHistory_EffectiveFrom(t *testing.T) {
	cutover := time.Date(2026, 7, 1, 0, 0, 0, 0, time.UTC)
	beforeCutover := cutover.Add(-time.Hour)
	afterCutover := cutover.Add(time.Hour)

	t.Run("uses cutover when ValidFrom is nil", func(t *testing.T) {
		h := &BackupScheduleHistory{}
		require.True(t, cutover.Equal(h.EffectiveFrom(cutover)))
	})

	t.Run("uses cutover when ValidFrom is earlier", func(t *testing.T) {
		h := &BackupScheduleHistory{ValidFrom: &beforeCutover}
		require.True(t, cutover.Equal(h.EffectiveFrom(cutover)))
	})

	t.Run("uses ValidFrom when later than cutover", func(t *testing.T) {
		h := &BackupScheduleHistory{ValidFrom: &afterCutover}
		require.True(t, afterCutover.Equal(h.EffectiveFrom(cutover)))
	})
}

func TestBackupScheduleHistory_EffectiveEnd(t *testing.T) {
	now := time.Date(2026, 7, 10, 10, 10, 0, 0, time.UTC)
	beforeNow := now.Add(-time.Hour)
	validTo := beforeNow.Add(30 * time.Minute)
	deletedAt := validTo.Add(15 * time.Minute)

	t.Run("uses now by default", func(t *testing.T) {
		h := &BackupScheduleHistory{}
		require.True(t, now.Equal(h.EffectiveEnd(now)))
	})

	t.Run("uses ValidTo when it ends sooner", func(t *testing.T) {
		h := &BackupScheduleHistory{ValidTo: &validTo}
		require.True(t, validTo.Equal(h.EffectiveEnd(now)))
	})

	t.Run("uses DeletedAt when it ends sooner", func(t *testing.T) {
		h := &BackupScheduleHistory{DeletedAt: &deletedAt}
		require.True(t, deletedAt.Equal(h.EffectiveEnd(now)))
	})

	t.Run("uses earliest of ValidTo and DeletedAt", func(t *testing.T) {
		h := &BackupScheduleHistory{ValidTo: &validTo, DeletedAt: &deletedAt}
		require.True(t, validTo.Equal(h.EffectiveEnd(now)))
	})
}

func TestBackupScheduleHistory_Contains(t *testing.T) {
	validFrom := time.Date(2026, 7, 8, 9, 0, 0, 0, time.UTC)
	validTo := time.Date(2026, 7, 10, 9, 0, 0, 0, time.UTC)
	deletedAt := time.Date(2026, 7, 9, 9, 0, 0, 0, time.UTC)
	history := &BackupScheduleHistory{
		ValidFrom: &validFrom,
		ValidTo:   &validTo,
	}

	t.Run("contains time inside interval", func(t *testing.T) {
		require.True(t, history.Contains(time.Date(2026, 7, 8, 10, 0, 0, 0, time.UTC)))
		require.True(t, history.Contains(time.Date(2026, 7, 9, 10, 0, 0, 0, time.UTC)))
	})

	t.Run("rejects time before ValidFrom", func(t *testing.T) {
		require.False(t, history.Contains(time.Date(2026, 7, 8, 8, 0, 0, 0, time.UTC)))
	})

	t.Run("rejects time at or after ValidTo", func(t *testing.T) {
		require.False(t, history.Contains(time.Date(2026, 7, 10, 10, 0, 0, 0, time.UTC)))
		require.False(t, history.Contains(validTo))
	})

	t.Run("rejects time at or after DeletedAt", func(t *testing.T) {
		h := &BackupScheduleHistory{
			ValidFrom: &validFrom,
			DeletedAt: &deletedAt,
		}
		require.False(t, h.Contains(time.Date(2026, 7, 9, 10, 0, 0, 0, time.UTC)))
		require.False(t, h.Contains(deletedAt))
	})
}

func TestNewBackupScheduleHistoryFromSchedule(t *testing.T) {
	createdAt := time.Date(2026, 7, 1, 0, 0, 0, 0, time.UTC)
	cutover := createdAt.Add(24 * time.Hour)
	previousValidTo := cutover.Add(24 * time.Hour)
	validTo := previousValidTo.Add(24 * time.Hour)
	schedule := &BackupSchedule{
		TenantID:      "1001",
		ClusterID:     "2002",
		Region:        "aws-us-east-1",
		ScheduleCron:  "0 0 10 * * *",
		Retention:     72,
		Kubernetes:    "test-k8s",
		CloudProvider: "AWS",
		CreatedAt:     &createdAt,
	}
	previous := &BackupScheduleHistory{ValidTo: &previousValidTo}

	t.Run("computes ValidFrom from CreatedAt, cutover and previous history", func(t *testing.T) {
		h := NewBackupScheduleHistoryFromSchedule(schedule, cutover, []*BackupScheduleHistory{previous}, nil)
		require.True(t, previousValidTo.Equal(*h.ValidFrom))
		require.Nil(t, h.ValidTo)
	})

	t.Run("uses cutover when it is later than CreatedAt", func(t *testing.T) {
		h := NewBackupScheduleHistoryFromSchedule(schedule, cutover, nil, nil)
		require.True(t, cutover.Equal(*h.ValidFrom))
	})

	t.Run("bounds previous history by validTo when archiving", func(t *testing.T) {
		afterValidTo := validTo.Add(time.Hour)
		unbounded := &BackupScheduleHistory{ValidTo: &afterValidTo}
		h := NewBackupScheduleHistoryFromSchedule(
			schedule,
			cutover,
			[]*BackupScheduleHistory{unbounded, previous},
			&validTo,
		)
		require.True(t, previousValidTo.Equal(*h.ValidFrom))
		require.NotNil(t, h.ValidTo)
		require.True(t, validTo.Equal(*h.ValidTo))
	})
}
