package errortracking

import (
	"fmt"
	"net/http/httptest"
	"net/url"
	"reflect"
	"testing"

	"github.com/stretchr/testify/require"
	"gitlab.com/gitlab-org/labkit/mask"
)

func TestCleanHeaders(t *testing.T) {
	tests := []struct {
		name        string
		url         string
		headers     map[string]string
		wantHeaders map[string]string
		wantQuery   string
	}{
		{
			name:        "trivial",
			url:         "/api/projects",
			headers:     map[string]string{},
			wantHeaders: map[string]string{},
			wantQuery:   "",
		},
		{
			name: "no_secrets",
			url:  "/api/projects?app=gitlab",
			headers: map[string]string{
				"User-Agent": "golang",
			},
			wantHeaders: map[string]string{
				"User-Agent": "golang",
			},
			wantQuery: "app=gitlab",
		},
		{
			name: "authorization_secret",
			url:  "/api/projects?authorization=secret1",
			headers: map[string]string{
				"User-Agent":    "golang",
				"Authorization": "secret2",
			},
			wantHeaders: map[string]string{
				"User-Agent":    "golang",
				"Authorization": mask.RedactionString,
			},
			wantQuery: fmt.Sprintf("authorization=%s", url.QueryEscape(mask.RedactionString)),
		},
		{
			name: "private_token_secret",
			url:  "/api/projects?private-token=secret1",
			headers: map[string]string{
				"User-Agent":    "golang",
				"Private-Token": "secret2",
			},
			wantHeaders: map[string]string{
				"User-Agent":    "golang",
				"Private-Token": mask.RedactionString,
			},
			wantQuery: fmt.Sprintf("private-token=%s", url.QueryEscape(mask.RedactionString)),
		},
		{
			name: "ending_with_token_secret",
			url:  "/api/projects?Sometoken=abc",
			headers: map[string]string{
				"User-Agent": "golang",
				"Sometoken":  "token",
			},
			wantHeaders: map[string]string{
				"User-Agent": "golang",
				"Sometoken":  mask.RedactionString,
			},
			wantQuery: fmt.Sprintf("Sometoken=%s", url.QueryEscape(mask.RedactionString)),
		},
		{
			name: "containing_password_secret",
			url:  "/api/projects?my_password_secret=pa55word",
			headers: map[string]string{
				"User-Agent":                 "golang",
				"X-Personal-Password-Secret": "password",
			},
			wantHeaders: map[string]string{
				"User-Agent":                 "golang",
				"X-Personal-Password-Secret": mask.RedactionString,
			},
			wantQuery: fmt.Sprintf("my_password_secret=%s", url.QueryEscape(mask.RedactionString)),
		},
		{
			name: "ending_key_secret",
			url:  "/api/projects?my_key=1212",
			headers: map[string]string{
				"User-Agent":       "golang",
				"Personalvaultkey": "Key",
			},
			wantHeaders: map[string]string{
				"User-Agent":       "golang",
				"Personalvaultkey": mask.RedactionString,
			},
			wantQuery: fmt.Sprintf("my_key=%s", url.QueryEscape(mask.RedactionString)),
		},
		{
			name: "containing_key",
			url:  "/api/projects",
			headers: map[string]string{
				"User-Agent":  "golang",
				"Keypassuser": "Not-Secret-String",
			},
			wantHeaders: map[string]string{
				"User-Agent":  "golang",
				"Keypassuser": "Not-Secret-String",
			},
		},
		{
			name: "multiple_secrets",
			url:  "/api/projects?token=123&token=456",
			headers: map[string]string{
				"User-Agent":    "golang",
				"Authorization": "secret1",
				"Private-Token": "secret2",
			},
			wantHeaders: map[string]string{
				"User-Agent":    "golang",
				"Authorization": mask.RedactionString,
				"Private-Token": mask.RedactionString,
			},
			wantQuery: fmt.Sprintf("token=%s&token=%s", url.QueryEscape(mask.RedactionString), url.QueryEscape(mask.RedactionString)),
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			req := httptest.NewRequest("GET", tt.url, nil)
			for k, v := range tt.headers {
				req.Header.Set(k, v)
			}

			result := redactRequestInfo(req)
			processedRequestHeaders := result.Headers

			require.True(t, reflect.DeepEqual(tt.wantHeaders, processedRequestHeaders), "Expected %+v, got %+v", tt.wantHeaders, processedRequestHeaders)
			require.Equal(t, tt.wantQuery, result.QueryString, "Expected query %+v, got %+v", tt.wantQuery, result.QueryString)
		})
	}
}
