package config

import (
	"testing"

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

func TestDeploymentMatcher_Match(t *testing.T) {
	t.Parallel()
	testCases := []struct {
		name     string
		matcher  *DeploymentMatcher
		region   string
		provider string
		expected bool
	}{
		{
			name: "Match both region and provider",
			matcher: &DeploymentMatcher{
				Regions:   []string{"us-west-1", "us-west-2"},
				Providers: []string{"aws", "gcp"},
			},
			region:   "us-west-2",
			provider: "aws",
			expected: true,
		},
		{
			name: "Match region, provider mismatch",
			matcher: &DeploymentMatcher{
				Regions:   []string{"us-west-1", "us-west-2"},
				Providers: []string{"aws", "gcp"},
			},
			region:   "us-west-1",
			provider: "azure",
			expected: false,
		},
		{
			name: "Match provider, region mismatch",
			matcher: &DeploymentMatcher{
				Regions:   []string{"us-west-1", "us-west-2"},
				Providers: []string{"aws", "gcp"},
			},
			region:   "us-east-1",
			provider: "gcp",
			expected: false,
		},
		{
			name: "Match neither",
			matcher: &DeploymentMatcher{
				Regions:   []string{"us-west-1"},
				Providers: []string{"aws"},
			},
			region:   "us-east-1",
			provider: "azure",
			expected: false,
		},
		{
			name: "Empty lists in matcher",
			matcher: &DeploymentMatcher{
				Regions:   []string{},
				Providers: []string{},
			},
			region:   "us-west-1",
			provider: "aws",
			expected: false,
		},
		{
			name: "Nil lists in matcher",
			matcher: &DeploymentMatcher{
				Regions:   nil,
				Providers: nil,
			},
			region:   "us-west-1",
			provider: "aws",
			expected: false,
		},
		{
			name: "Empty input strings",
			matcher: &DeploymentMatcher{
				Regions:   []string{"us-west-1"},
				Providers: []string{"aws"},
			},
			region:   "",
			provider: "",
			expected: false,
		},
		{
			name: "Empty strings contained in lists",
			matcher: &DeploymentMatcher{
				Regions:   []string{"us-west-1", ""},
				Providers: []string{"aws", ""},
			},
			region:   "",
			provider: "",
			expected: true, // Assuming utils.IsContain matches empty strings
		},
		{
			name: "Case sensitivity check (assuming IsContain is case-sensitive)",
			matcher: &DeploymentMatcher{
				Regions:   []string{"us-west-1"},
				Providers: []string{"AWS"}, // Uppercase
			},
			region:   "us-west-1",
			provider: "aws",
			expected: false,
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			t.Parallel()
			result := tc.matcher.Match(tc.region, tc.provider)
			assert.Equal(t, tc.expected, result, "Mismatch in expected result")
		})
	}
}

func TestAllowListMatcher_Match(t *testing.T) {
	t.Parallel()

	matchingDeploymentMatcher := &DeploymentMatcher{
		Regions:   []string{"us-west-2"},
		Providers: []string{"aws"},
	}
	mismatchingDeploymentMatcher := &DeploymentMatcher{
		Regions:   []string{"us-east-1"},
		Providers: []string{"gcp"},
	}

	testCases := []struct {
		name          string
		matcher       *AllowListMatcher
		tenantID      uint64
		projectID     uint64
		clusterID     uint64
		region        string
		infraProvider string
		expected      bool
	}{
		{
			name: "Match TenantID, no deployment matcher",
			matcher: &AllowListMatcher{
				TenantID: []string{"100", "101"},
			},
			tenantID: 101,
			expected: true,
		},
		{
			name: "Match ProjectID, no deployment matcher",
			matcher: &AllowListMatcher{
				ProjectID: []string{"200", "201"},
			},
			projectID: 200,
			expected:  true,
		},
		{
			name: "Match ClusterID, no deployment matcher",
			matcher: &AllowListMatcher{
				ClusterID: []string{"300"},
			},
			clusterID: 300,
			expected:  true,
		},
		{
			name: "Match none, no deployment matcher",
			matcher: &AllowListMatcher{
				TenantID:  []string{"1"},
				ProjectID: []string{"2"},
				ClusterID: []string{"3"},
			},
			tenantID:  10,
			projectID: 20,
			clusterID: 30,
			expected:  false,
		},
		{
			name: "Match TenantID (from zero value), no deployment matcher",
			matcher: &AllowListMatcher{
				TenantID: []string{"0"},
			},
			tenantID: 0,
			expected: true,
		},

		{
			name: "Match TenantID, with matching DeploymentMatcher",
			matcher: &AllowListMatcher{
				TenantID:          []string{"100"},
				DeploymentMatcher: matchingDeploymentMatcher,
			},
			tenantID:      100,
			region:        "us-west-2",
			infraProvider: "aws",
			expected:      true,
		},
		{
			name: "Match ProjectID, with matching DeploymentMatcher",
			matcher: &AllowListMatcher{
				ProjectID:         []string{"200"},
				DeploymentMatcher: matchingDeploymentMatcher,
			},
			projectID:     200,
			region:        "us-west-2",
			infraProvider: "aws",
			expected:      true,
		},
		{
			name: "Match TenantID, with MISMATCHING DeploymentMatcher",
			matcher: &AllowListMatcher{
				TenantID:          []string{"100"},
				DeploymentMatcher: mismatchingDeploymentMatcher,
			},
			tenantID:      100,
			region:        "us-west-2",
			infraProvider: "aws",
			expected:      false,
		},
		{
			name: "Match none (ID), with matching DeploymentMatcher",
			matcher: &AllowListMatcher{
				TenantID:          []string{"100"},
				DeploymentMatcher: matchingDeploymentMatcher,
			},
			tenantID:      101,
			region:        "us-west-2",
			infraProvider: "aws",
			expected:      false,
		},
		{
			name: "Match all (ID and Deployment)",
			matcher: &AllowListMatcher{
				TenantID:          []string{"100"},
				ProjectID:         []string{"200"},
				ClusterID:         []string{"300"},
				DeploymentMatcher: matchingDeploymentMatcher,
			},
			tenantID:      100,
			projectID:     999,
			region:        "us-west-2",
			infraProvider: "aws",
			expected:      true,
		},
		{
			name: "Nil DeploymentMatcher (should be treated as no deployment matcher)",
			matcher: &AllowListMatcher{
				TenantID:          []string{"100"},
				DeploymentMatcher: nil,
			},
			tenantID: 100,
			region:   "any-region",
			expected: true,
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			t.Parallel()

			result := tc.matcher.Match(tc.tenantID, tc.projectID, tc.clusterID, tc.region, tc.infraProvider)
			assert.Equal(t, tc.expected, result, "Mismatch in expected result")
		})
	}
}
