package secpolicies

import (
	"testing"
)

var testSecurityPolicies = SecurityPolicyList{
	{
		ID:                        "policy1",
		DisplayName:               "DevelopersPolicy",
		Description:               "First policy",
		CreatedAt:                 "2023-01-01",
		UpdatedAt:                 "2023-01-10",
		AccessGroupID:             "group1",
		AccessGroupName:           "Developers",
		AppliedToNetObjectGroupID: "netgroup1",
		Enabled:                   true,
		StartPriority:             1,
		EndPriority:               100,
		VersionID:                 1,
		Status: Status{
			Common: "active",
			Hypervisors: []HypervisorStatus{
				{
					Name:             "hyp1",
					DisplayName:      "Hypervisor1",
					Status:           "synced",
					HypervisorStatus: "healthy",
					SyncedAt:         "2023-01-10T10:00:00Z",
				},
			},
		},
		SecurityRules: []SecurityRule{
			{
				ID:                "rule1",
				DisplayName:       "AllowHTTP",
				Description:       "Allow HTTP traffic",
				Action:            "Allow",
				Direction:         "Ingress",
				Enabled:           true,
				Priority:          10,
				SecurityPolicyID:  "policy1",
				LogEnabled:        true,
				LogSeverity:       "medium",
				StatisticsEnabled: true,
				VersionID:         1,
				Filter: Filter{
					Filters: map[string]interface{}{
						"protocol": "tcp",
						"port":     float64(80),
					},
				},
			},
		},
	},
	{
		ID:                        "policy2",
		DisplayName:               "AdminsPolicy",
		Description:               "Second policy",
		CreatedAt:                 "2023-01-02",
		UpdatedAt:                 "2023-01-11",
		AccessGroupID:             "group2",
		AccessGroupName:           "Admins",
		AppliedToNetObjectGroupID: "netgroup2",
		Enabled:                   false,
		StartPriority:             101,
		EndPriority:               200,
		VersionID:                 2,
		Status: Status{
			Common: "inactive",
			Hypervisors: []HypervisorStatus{
				{
					Name:             "hyp2",
					DisplayName:      "Hypervisor2",
					Status:           "pending",
					HypervisorStatus: "syncing",
					SyncedAt:         "2023-01-11T10:00:00Z",
				},
			},
		},
		SecurityRules: []SecurityRule{
			{
				ID:                "rule2",
				DisplayName:       "DenySSH",
				Description:       "Deny SSH traffic",
				Action:            "Deny",
				Direction:         "Ingress",
				Enabled:           true,
				Priority:          20,
				SecurityPolicyID:  "policy2",
				LogEnabled:        false,
				LogSeverity:       "high",
				StatisticsEnabled: false,
				VersionID:         1,
				Filter: Filter{
					Filters: map[string]interface{}{
						"protocol": "tcp",
						"port":     float64(22),
					},
				},
			},
		},
	},
	{
		ID:                        "policy3",
		DisplayName:               "UsersPolicy",
		Description:               "Third policy",
		CreatedAt:                 "2023-01-03",
		UpdatedAt:                 "2023-01-12",
		AccessGroupID:             "group3",
		AccessGroupName:           "Users",
		AppliedToNetObjectGroupID: "netgroup3",
		Enabled:                   true,
		StartPriority:             201,
		EndPriority:               300,
		VersionID:                 3,
		Status: Status{
			Common: "active",
			Hypervisors: []HypervisorStatus{
				{
					Name:             "hyp3",
					DisplayName:      "Hypervisor3",
					Status:           "synced",
					HypervisorStatus: "healthy",
					SyncedAt:         "2023-01-12T10:00:00Z",
				},
			},
		},
		SecurityRules: []SecurityRule{
			{
				ID:                "rule3",
				DisplayName:       "AllowHTTPS",
				Description:       "Allow HTTPS traffic",
				Action:            "Allow",
				Direction:         "Egress",
				Enabled:           true,
				Priority:          30,
				SecurityPolicyID:  "policy3",
				LogEnabled:        true,
				LogSeverity:       "low",
				StatisticsEnabled: true,
				VersionID:         1,
				Filter: Filter{
					Filters: map[string]interface{}{
						"protocol": "tcp",
						"port":     float64(443),
					},
				},
			},
		},
	},
}

func TestFilterByID(t *testing.T) {
	actual := testSecurityPolicies.FilterByID("policy2").FindOne()

	if actual.ID != "policy2" {
		t.Fatal("actual:", actual.ID, "> expected: policy2")
	}
}

func TestFilterByDisplayName(t *testing.T) {
	actual := testSecurityPolicies.FilterByName("UsersPolicy").FindOne()

	if actual.DisplayName != "UsersPolicy" {
		t.Fatal("actual:", actual.DisplayName, ">> expected: UsersPolicy")
	}
}

func TestFilterFunc(t *testing.T) {
	actual := testSecurityPolicies.FilterFunc(func(sp SecurityPolicySummary) bool {
		return sp.Description == "Second policy"
	})

	if len(actual) != 1 || actual[0].ID != "policy2" {
		t.Fatal("Expected 1 policy with description 'Second policy', found:", len(actual))
	}
}

func TestFindOneWithResults(t *testing.T) {
	result := testSecurityPolicies.FilterByID("policy1").FindOne()
	if result.ID != "policy1" {
		t.Fatal("Expected policy1, got:", result.ID)
	}
}

func TestFindOneEmpty(t *testing.T) {
	emptyList := SecurityPolicyList{}
	result := emptyList.FindOne()

	if result.ID != "" || result.DisplayName != "" {
		t.Fatal("Expected empty SecurityPolicySummary, got:", result)
	}
}

func TestFilterByIDNotFound(t *testing.T) {
	actual := testSecurityPolicies.FilterByID("nonexistent")

	if len(actual) != 0 {
		t.Fatal("Expected 0 policies, found:", len(actual))
	}
}

func TestFilterByDisplayNameNotFound(t *testing.T) {
	actual := testSecurityPolicies.FilterByName("Nonexistent Policy")

	if len(actual) != 0 {
		t.Fatal("Expected 0 policies, found:", len(actual))
	}
}

func TestFilterByEnabled(t *testing.T) {
	actual := testSecurityPolicies.FilterFunc(func(sp SecurityPolicySummary) bool {
		return sp.Enabled
	})

	if len(actual) != 2 {
		t.Fatal("Expected 2 enabled policies, found:", len(actual))
	}
}

func TestFilterByAccessGroup(t *testing.T) {
	actual := testSecurityPolicies.FilterFunc(func(sp SecurityPolicySummary) bool {
		return sp.AccessGroupName == "Developers"
	})

	if len(actual) != 1 || actual[0].ID != "policy1" {
		t.Fatal("Expected 1 policy for Developers group, found:", len(actual))
	}
}

func TestFilterByStatus(t *testing.T) {
	actual := testSecurityPolicies.FilterFunc(func(sp SecurityPolicySummary) bool {
		return sp.Status.Common == "active"
	})

	if len(actual) != 2 {
		t.Fatal("Expected 2 active policies, found:", len(actual))
	}
}

func TestFilterByPriorityRange(t *testing.T) {
	actual := testSecurityPolicies.FilterFunc(func(sp SecurityPolicySummary) bool {
		return sp.StartPriority >= 100 && sp.EndPriority <= 200
	})

	if len(actual) != 1 || actual[0].ID != "policy2" {
		t.Fatal("Expected 1 policy in priority range 100-200, found:", len(actual))
	}
}

func TestFilterByRuleAction(t *testing.T) {
	actual := testSecurityPolicies.FilterFunc(func(sp SecurityPolicySummary) bool {
		for _, rule := range sp.SecurityRules {
			if rule.Action == "Deny" {
				return true
			}
		}
		return false
	})

	if len(actual) != 1 || actual[0].ID != "policy2" {
		t.Fatal("Expected 1 policy with Deny rule, found:", len(actual))
	}
}

func TestFilterByRuleDirection(t *testing.T) {
	actual := testSecurityPolicies.FilterFunc(func(sp SecurityPolicySummary) bool {
		for _, rule := range sp.SecurityRules {
			if rule.Direction == "Egress" {
				return true
			}
		}
		return false
	})

	if len(actual) != 1 || actual[0].ID != "policy3" {
		t.Fatal("Expected 1 policy with Egress rule, found:", len(actual))
	}
}

func TestFilterByLogEnabled(t *testing.T) {
	actual := testSecurityPolicies.FilterFunc(func(sp SecurityPolicySummary) bool {
		for _, rule := range sp.SecurityRules {
			if rule.LogEnabled {
				return true
			}
		}
		return false
	})

	if len(actual) != 2 {
		t.Fatal("Expected 2 policies with log enabled rules, found:", len(actual))
	}
}
