package config

import (
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
)

func TestCompactConfig_GetCompactCycle(t *testing.T) {
	tests := []struct {
		name      string
		config    CompactConfig
		clusterID uint64
		tenantID  uint64
		projectID uint64
		region    string
		expected  string
	}{
		{
			name: "Global default when no overrides",
			config: CompactConfig{
				CompactBackupCycle: "5h50m",
			},
			clusterID: 123,
			tenantID:  456,
			projectID: 789,
			region:    "us-west-1",
			expected:  "5h50m",
		},
		{
			name: "Cluster-level override takes highest priority",
			config: CompactConfig{
				CompactBackupCycle: "5h50m",
				CompactOverrides: &CompactOverrideConfig{
					RegionDefaults: map[string]CompactOverride{
						"us-west-1": {Cycle: "4h"},
					},
					CustomerOverrides: []CompactOverride{
						{
							TenantID: "456",
							Region:   "us-west-1",
							Level:    "tenant",
							Cycle:    "3h",
						},
						{
							TenantID:  "456",
							ProjectID: "789",
							Region:    "us-west-1",
							Level:     "project",
							Cycle:     "2h",
						},
						{
							ClusterID: "123",
							Level:     "cluster",
							Cycle:     "1h",
						},
					},
				},
			},
			clusterID: 123,
			tenantID:  456,
			projectID: 789,
			region:    "us-west-1",
			expected:  "1h",
		},
		{
			name: "Project-level override when no cluster override",
			config: CompactConfig{
				CompactBackupCycle: "5h50m",
				CompactOverrides: &CompactOverrideConfig{
					CustomerOverrides: []CompactOverride{
						{
							TenantID:  "456",
							ProjectID: "789",
							Region:    "us-west-1",
							Level:     "project",
							Cycle:     "2h",
						},
						{
							TenantID: "456",
							Region:   "us-west-1",
							Level:    "tenant",
							Cycle:    "3h",
						},
					},
				},
			},
			clusterID: 999, // Different cluster ID
			tenantID:  456,
			projectID: 789,
			region:    "us-west-1",
			expected:  "2h",
		},
		{
			name: "Tenant-level override when no project or cluster override",
			config: CompactConfig{
				CompactBackupCycle: "5h50m",
				CompactOverrides: &CompactOverrideConfig{
					CustomerOverrides: []CompactOverride{
						{
							TenantID: "456",
							Region:   "us-west-1",
							Level:    "tenant",
							Cycle:    "3h",
						},
					},
				},
			},
			clusterID: 999,
			tenantID:  456,
			projectID: 999, // Different project ID
			region:    "us-west-1",
			expected:  "3h",
		},
		{
			name: "Region default when no customer overrides match",
			config: CompactConfig{
				CompactBackupCycle: "5h50m",
				CompactOverrides: &CompactOverrideConfig{
					RegionDefaults: map[string]CompactOverride{
						"us-west-1": {Cycle: "4h"},
						"us-east-1": {Cycle: "6h"},
					},
				},
			},
			clusterID: 123,
			tenantID:  456,
			projectID: 789,
			region:    "us-west-1",
			expected:  "4h",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := tt.config.GetCompactCycle(tt.clusterID, tt.tenantID, tt.projectID, tt.region)
			assert.Equal(t, tt.expected, result)
		})
	}
}

func TestCompactConfig_GetCompactConcurrency(t *testing.T) {
	concurrency64 := 64
	concurrency128 := 128
	concurrency256 := 256

	tests := []struct {
		name      string
		config    CompactConfig
		clusterID uint64
		tenantID  uint64
		projectID uint64
		region    string
		expected  int
	}{
		{
			name: "Global default when no overrides",
			config: CompactConfig{
				CompactBackupConcurrency: 32,
			},
			clusterID: 123,
			tenantID:  456,
			projectID: 789,
			region:    "us-west-1",
			expected:  32,
		},
		{
			name: "Cluster-level override",
			config: CompactConfig{
				CompactBackupConcurrency: 32,
				CompactOverrides: &CompactOverrideConfig{
					CustomerOverrides: []CompactOverride{
						{
							ClusterID:   "123",
							Level:       "cluster",
							Concurrency: &concurrency256,
						},
					},
				},
			},
			clusterID: 123,
			tenantID:  456,
			projectID: 789,
			region:    "us-west-1",
			expected:  256,
		},
		{
			name: "Region default override",
			config: CompactConfig{
				CompactBackupConcurrency: 32,
				CompactOverrides: &CompactOverrideConfig{
					RegionDefaults: map[string]CompactOverride{
						"us-west-1": {Concurrency: &concurrency64},
					},
				},
			},
			clusterID: 123,
			tenantID:  456,
			projectID: 789,
			region:    "us-west-1",
			expected:  64,
		},
		{
			name: "Tenant-level override",
			config: CompactConfig{
				CompactBackupConcurrency: 32,
				CompactOverrides: &CompactOverrideConfig{
					CustomerOverrides: []CompactOverride{
						{
							TenantID:    "456",
							Region:      "us-west-1",
							Level:       "tenant",
							Concurrency: &concurrency128,
						},
					},
				},
			},
			clusterID: 123,
			tenantID:  456,
			projectID: 789,
			region:    "us-west-1",
			expected:  128,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := tt.config.GetCompactConcurrency(tt.clusterID, tt.tenantID, tt.projectID, tt.region)
			assert.Equal(t, tt.expected, result)
		})
	}
}

func TestCompactConfig_GetCompactCleanPolicy(t *testing.T) {
	tests := []struct {
		name      string
		config    CompactConfig
		clusterID uint64
		tenantID  uint64
		projectID uint64
		region    string
		expected  string
	}{
		{
			name: "Global default Retain",
			config: CompactConfig{
				CompactBackupCleanPolicy: "Retain",
			},
			clusterID: 123,
			tenantID:  456,
			projectID: 789,
			region:    "us-west-1",
			expected:  "Retain",
		},
		{
			name: "Cluster-level override to Delete",
			config: CompactConfig{
				CompactBackupCleanPolicy: "Retain",
				CompactOverrides: &CompactOverrideConfig{
					CustomerOverrides: []CompactOverride{
						{
							ClusterID:   "123",
							Level:       "cluster",
							CleanPolicy: "Delete",
						},
					},
				},
			},
			clusterID: 123,
			tenantID:  456,
			projectID: 789,
			region:    "us-west-1",
			expected:  "Delete",
		},
		{
			name: "Project-level override",
			config: CompactConfig{
				CompactBackupCleanPolicy: "Retain",
				CompactOverrides: &CompactOverrideConfig{
					CustomerOverrides: []CompactOverride{
						{
							TenantID:    "456",
							ProjectID:   "789",
							Region:      "us-west-1",
							Level:       "project",
							CleanPolicy: "Delete",
						},
					},
				},
			},
			clusterID: 999, // Different cluster
			tenantID:  456,
			projectID: 789,
			region:    "us-west-1",
			expected:  "Delete",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := tt.config.GetCompactCleanPolicy(tt.clusterID, tt.tenantID, tt.projectID, tt.region)
			assert.Equal(t, tt.expected, result)
		})
	}
}

func TestCompactConfig_GetCompactMinStartTSWithOverride(t *testing.T) {
	tests := []struct {
		name        string
		config      CompactConfig
		clusterID   uint64
		tenantID    uint64
		projectID   uint64
		region      string
		expected    *uint64
		expectError bool
	}{
		{
			name: "Global default empty returns nil",
			config: CompactConfig{
				CompactMinStartTS: "",
			},
			clusterID: 123,
			tenantID:  456,
			projectID: 789,
			region:    "us-west-1",
			expected:  nil,
		},
		{
			name: "Global default with value",
			config: CompactConfig{
				CompactMinStartTS: "1234567890",
			},
			clusterID: 123,
			tenantID:  456,
			projectID: 789,
			region:    "us-west-1",
			expected:  uint64Ptr(uint64(1234567890)),
		},
		{
			name: "Cluster-level override",
			config: CompactConfig{
				CompactMinStartTS: "1234567890",
				CompactOverrides: &CompactOverrideConfig{
					CustomerOverrides: []CompactOverride{
						{
							ClusterID:  "123",
							Level:      "cluster",
							MinStartTS: "9876543210",
						},
					},
				},
			},
			clusterID: 123,
			tenantID:  456,
			projectID: 789,
			region:    "us-west-1",
			expected:  uint64Ptr(uint64(9876543210)),
		},
		{
			name: "Invalid MinStartTS returns error",
			config: CompactConfig{
				CompactMinStartTS: "invalid",
			},
			clusterID:   123,
			tenantID:    456,
			projectID:   789,
			region:      "us-west-1",
			expectError: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result, err := tt.config.GetCompactMinStartTSWithOverride(tt.clusterID, tt.tenantID, tt.projectID, tt.region)
			if tt.expectError {
				assert.Error(t, err)
			} else {
				assert.NoError(t, err)
				if tt.expected == nil {
					assert.Nil(t, result)
				} else {
					assert.NotNil(t, result)
					assert.Equal(t, *tt.expected, *result)
				}
			}
		})
	}
}

func TestCompactConfig_GetCompactCycleDuration(t *testing.T) {
	tests := []struct {
		name        string
		config      CompactConfig
		clusterID   uint64
		tenantID    uint64
		projectID   uint64
		region      string
		expected    time.Duration
		expectError bool
	}{
		{
			name: "Valid duration string",
			config: CompactConfig{
				CompactBackupCycle: "5h30m",
			},
			clusterID: 123,
			tenantID:  456,
			projectID: 789,
			region:    "us-west-1",
			expected:  5*time.Hour + 30*time.Minute,
		},
		{
			name: "Invalid duration string returns error",
			config: CompactConfig{
				CompactBackupCycle: "invalid",
			},
			clusterID:   123,
			tenantID:    456,
			projectID:   789,
			region:      "us-west-1",
			expectError: true,
		},
		{
			name: "Override with valid duration",
			config: CompactConfig{
				CompactBackupCycle: "5h30m",
				CompactOverrides: &CompactOverrideConfig{
					CustomerOverrides: []CompactOverride{
						{
							ClusterID: "123",
							Level:     "cluster",
							Cycle:     "2h15m",
						},
					},
				},
			},
			clusterID: 123,
			tenantID:  456,
			projectID: 789,
			region:    "us-west-1",
			expected:  2*time.Hour + 15*time.Minute,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result, err := tt.config.GetCompactCycleDuration(tt.clusterID, tt.tenantID, tt.projectID, tt.region)
			if tt.expectError {
				assert.Error(t, err)
			} else {
				assert.NoError(t, err)
				assert.Equal(t, tt.expected, result)
			}
		})
	}
}

// Helper function to create pointer to uint64
func uint64Ptr(v uint64) *uint64 {
	return &v
}
