package custom_detectors

import (
	"testing"
)

func TestCustomDetectorsKeywordValidation(t *testing.T) {
	tests := []struct {
		name    string
		input   []string
		wantErr bool
	}{
		{
			name:    "Test empty list of keywords",
			input:   []string{},
			wantErr: true,
		},
		{
			name:    "Test empty keyword",
			input:   []string{""},
			wantErr: true,
		},
		{
			name:    "Test valid keywords",
			input:   []string{"hello", "world"},
			wantErr: false,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got := ValidateKeywords(tt.input)

			if (got != nil && !tt.wantErr) || (got == nil && tt.wantErr) {
				t.Errorf("ValidateKeywords() error = %v, wantErr %v", got, tt.wantErr)
			}
		})
	}
}

func TestCustomDetectorsRegexValidation(t *testing.T) {
	tests := []struct {
		name    string
		input   map[string]string
		wantErr bool
	}{
		{
			name: "Test list of keywords",
			input: map[string]string{
				"id_pat_example": "([a-zA-Z0-9]{32})",
			},
			wantErr: false,
		},
		{
			name:    "Test empty list of keywords",
			input:   map[string]string{},
			wantErr: true,
		},
		{
			name: "Test invalid regex",
			input: map[string]string{
				"test": "!!?(?:?)[a-zA-Z0-9]{32}",
			},
			wantErr: true,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got := ValidateRegex(tt.input)

			if (got != nil && !tt.wantErr) || (got == nil && tt.wantErr) {
				t.Errorf("ValidateRegex() error = %v, wantErr %v", got, tt.wantErr)
			}
		})
	}
}

func TestCustomDetectorsVerifyEndpointValidation(t *testing.T) {
	tests := []struct {
		name     string
		endpoint string
		unsafe   bool
		wantErr  bool
	}{
		{
			name:     "Test http endpoint with unsafe flag",
			endpoint: "http://localhost:8000/{id_pat_example}",
			unsafe:   true,
			wantErr:  false,
		},
		{
			name:     "Test http endpoint without unsafe flag",
			endpoint: "http://localhost:8000/{id_pat_example}",
			unsafe:   false,
			wantErr:  true,
		},
		{
			name:     "Test https endpoint with unsafe flag",
			endpoint: "https://localhost:8000/{id_pat_example}",
			unsafe:   true,
			wantErr:  false,
		},
		{
			name:     "Test https endpoint without unsafe flag",
			endpoint: "https://localhost:8000/{id_pat_example}",
			unsafe:   false,
			wantErr:  false,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got := ValidateVerifyEndpoint(tt.endpoint, tt.unsafe)

			if (got != nil && !tt.wantErr) || (got == nil && tt.wantErr) {
				t.Errorf("ValidateVerifyEndpoint() error = %v, wantErr %v", got, tt.wantErr)
			}
		})
	}
}

func TestCustomDetectorsVerifyHeadersValidation(t *testing.T) {
	tests := []struct {
		name    string
		headers []string
		wantErr bool
	}{
		{
			name:    "Test single header",
			headers: []string{"Authorization: Bearer {secret_pat_example.0}"},
			wantErr: false,
		},
		{
			name:    "Test invalid header",
			headers: []string{"Hello world"},
			wantErr: true,
		},
		{
			name:    "Test ugly header",
			headers: []string{"Hello:::::::world::hi:"},
			wantErr: false,
		},
		{
			name:    "Test empty header",
			headers: []string{},
			wantErr: false,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got := ValidateVerifyHeaders(tt.headers)

			if (got != nil && !tt.wantErr) || (got == nil && tt.wantErr) {
				t.Errorf("ValidateVerifyHeaders() error = %v, wantErr %v", got, tt.wantErr)
			}
		})
	}
}

func TestCustomDetectorsVerifyRangeValidation(t *testing.T) {
	tests := []struct {
		name    string
		ranges  []string
		wantErr bool
	}{
		{
			name:    "Test multiple mixed ranges",
			ranges:  []string{"200", "300-350"},
			wantErr: false,
		},
		{
			name:    "Test invalid non-number range",
			ranges:  []string{"hi"},
			wantErr: true,
		},
		{
			name:    "Test invalid lower to upper range",
			ranges:  []string{"200-100"},
			wantErr: true,
		},
		{
			name:    "Test invalid http range",
			ranges:  []string{"400-1000"},
			wantErr: true,
		},
		{
			name:    "Test multiple ranges with invalid inputs",
			ranges:  []string{"322", "hello-world", "100-200"},
			wantErr: true,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got := ValidateVerifyRanges(tt.ranges)

			if (got != nil && !tt.wantErr) || (got == nil && tt.wantErr) {
				t.Errorf("ValidateVerifyRanges() error = %v, wantErr %v", got, tt.wantErr)
			}
		})
	}
}

func TestStatusCodeMatchesRanges(t *testing.T) {
	tests := []struct {
		name   string
		code   int
		ranges []string
		want   bool
	}{
		{
			name:   "single code match",
			code:   200,
			ranges: []string{"200"},
			want:   true,
		},
		{
			name:   "single code no match",
			code:   201,
			ranges: []string{"200"},
			want:   false,
		},
		{
			name:   "range lower bound",
			code:   200,
			ranges: []string{"200-250"},
			want:   true,
		},
		{
			name:   "range upper bound",
			code:   250,
			ranges: []string{"200-250"},
			want:   true,
		},
		{
			name:   "range middle",
			code:   225,
			ranges: []string{"200-250"},
			want:   true,
		},
		{
			name:   "range outside below",
			code:   199,
			ranges: []string{"200-250"},
			want:   false,
		},
		{
			name:   "range outside above",
			code:   251,
			ranges: []string{"200-250"},
			want:   false,
		},
		{
			name:   "multiple ranges first match",
			code:   200,
			ranges: []string{"200", "300-399"},
			want:   true,
		},
		{
			name:   "multiple ranges second match",
			code:   301,
			ranges: []string{"200", "300-399"},
			want:   true,
		},
		{
			name:   "multiple ranges no match",
			code:   500,
			ranges: []string{"200", "300-399"},
			want:   false,
		},
		{
			name:   "empty ranges",
			code:   200,
			ranges: nil,
			want:   false,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got := StatusCodeMatchesRanges(tt.code, tt.ranges)
			if got != tt.want {
				t.Errorf("StatusCodeMatchesRanges(%d, %v) = %v, want %v", tt.code, tt.ranges, got, tt.want)
			}
		})
	}
}

func TestCustomDetectorsVerifyRegexVarsValidation(t *testing.T) {
	tests := []struct {
		name    string
		regex   map[string]string
		body    string
		wantErr bool
	}{
		{
			name:    "Regex defined but not used in body",
			regex:   map[string]string{"id": "[0-9]{1,10}", "id_pat_example": "([a-zA-Z0-9]{32})"},
			body:    "hello world",
			wantErr: false,
		},
		{
			name:    "Regex defined and is used in body",
			regex:   map[string]string{"id": "[0-9]{1,10}", "id_pat_example": "([a-zA-Z0-9]{32})"},
			body:    "hello world {id}",
			wantErr: false,
		},
		{
			name:    "Regex var in body but not defined",
			regex:   map[string]string{"id": "[0-9]{1,10}", "id_pat_example": "([a-zA-Z0-9]{32})"},
			body:    "hello world {hello}",
			wantErr: true,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got := ValidateRegexVars(tt.regex, tt.body)

			if (got != nil && !tt.wantErr) || (got == nil && tt.wantErr) {
				t.Errorf("ValidateRegexVars() error = %v, wantErr %v", got, tt.wantErr)
			}
		})
	}
}

func TestContainsDigit(t *testing.T) {
	type args struct {
		s string
	}
	tests := []struct {
		name string
		args args
		want bool
	}{
		{
			name: "contains digit",
			args: args{s: "lzscqf&60M"},
			want: true,
		},
		{
			name: "does not contains digit",
			args: args{s: "ZlDQOdaM*vsT"},
			want: false,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := ContainsDigit(tt.args.s); got != tt.want {
				t.Errorf("ContainsDigit() = %v, want %v", got, tt.want)
			}
		})
	}
}

func TestContainsLowercase(t *testing.T) {
	type args struct {
		s string
	}
	tests := []struct {
		name string
		args args
		want bool
	}{
		{
			name: "contains lower case",
			args: args{s: "g0AJBHdnhRG2"},
			want: true,
		},
		{
			name: "does not contains lower case",
			args: args{s: "V7T#MEA6@+TN"},
			want: false,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := ContainsLowercase(tt.args.s); got != tt.want {
				t.Errorf("ContainsDigit() = %v, want %v", got, tt.want)
			}
		})
	}
}

func TestContainsUppercase(t *testing.T) {
	type args struct {
		s string
	}
	tests := []struct {
		name string
		args args
		want bool
	}{
		{
			name: "contains upper case",
			args: args{s: "G1sKkJeKlSQf"},
			want: true,
		},
		{
			name: "does not contains upper case",
			args: args{s: "pq6-14ydz1@d"},
			want: false,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := ContainsUppercase(tt.args.s); got != tt.want {
				t.Errorf("ContainsDigit() = %v, want %v", got, tt.want)
			}
		})
	}
}

func TestContainsSpecialChar(t *testing.T) {
	type args struct {
		s string
	}
	tests := []struct {
		name string
		args args
		want bool
	}{
		{
			name: "contains upper case",
			args: args{s: "HP$gE7s=do0B"},
			want: true,
		},
		{
			name: "does not contains upper case",
			args: args{s: "w9gvBYctrSjB"},
			want: false,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := ContainsSpecialChar(tt.args.s); got != tt.want {
				t.Errorf("ContainsDigit() = %v, want %v", got, tt.want)
			}
		})
	}
}
