package alert

import (
	"strings"
	"testing"

	"github.com/pingcap-inc/clinic_cloud_server/pkg/db"
	"github.com/pingcap-inc/clinic_cloud_server/pkg/entity"
)

func TestNameRegexp(t *testing.T) {
	tests := []struct {
		name string
		want bool
	}{
		{"name1", true},
		{"name-with-dash", true},
		{"namemaxlengthnamemaxlengthnamemaxlengthnamemaxlengthnamemaxlengt", true},
		{"nametoolongnametoolongnametoolongnametoolongnametoolongnametoolon", false},
		{"nts", false},
		{"name-last-dash-", false},
		{"name with space", false},
		{"name.with.dot", false},
		{"name_with_underscore", false},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := nameRegexp.MatchString(tt.name); got != tt.want {
				t.Errorf("nameRegexp.MatchString() = %v, want %v", got, tt.want)
			}
		})
	}
}

func TestTokenRegexp(t *testing.T) {
	tests := []struct {
		name string
		want bool
	}{
		{"token1", true},
		{"token-with-dash", true},
		{"token_with_underscore", true},
		{"token.with.dot", true},
		{"tokenmaxlengthtokenmaxlengthtokenmaxlengthtokenmaxlengthtokenmaxlengthtokenmaxlengthtokenmaxlengthtokenmaxlengthtokenmaxlengthto", true},
		{"tokentoolongtokentoolongtokentoolongtokentoolongtokentoolongtokentoolongtokentoolongtokentoolongtokentoolongtokentoolongtokentool", false},
		{"token with space", false},
		{"token=with=equal", false},
		{"token/with/slash", false},
		{"token+with+plus", false},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := tokenRegexp.MatchString(tt.name); got != tt.want {
				t.Errorf("tokenRegexp.MatchString() = %v, want %v", got, tt.want)
			}
		})
	}
}

func TestCheckURL(t *testing.T) {
	tests := []struct {
		name    string
		url     string
		wantErr bool
	}{
		{name: "https", url: "https://hooks.example.com/alert", wantErr: false},
		{name: "http", url: "http://hooks.example.com/alert", wantErr: false},
		{name: "missing scheme", url: "hooks.example.com/alert", wantErr: true},
		{name: "unsupported scheme", url: "ftp://hooks.example.com/alert", wantErr: true},
		{name: "missing host", url: "https:///alert", wantErr: true},
		{name: "userinfo", url: "https://user:password@hooks.example.com/alert", wantErr: true},
		{name: "localhost", url: "http://localhost/alert", wantErr: true},
		{name: "loopback ipv4", url: "http://127.0.0.1/alert", wantErr: true},
		{name: "private ipv4", url: "http://10.0.0.1/alert", wantErr: true},
		{name: "link local ipv4", url: "http://169.254.169.254/alert", wantErr: true},
		{name: "loopback ipv6", url: "http://[::1]/alert", wantErr: true},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := checkURL(tt.url)
			if (err != nil) != tt.wantErr {
				t.Errorf("checkURL(%q) error = %v, wantErr %v", tt.url, err, tt.wantErr)
			}
		})
	}
}

func TestCheckLarkWebhookURL(t *testing.T) {
	tests := []struct {
		name    string
		url     string
		wantErr bool
	}{
		{
			name:    "lark",
			url:     "https://open.larksuite.com/open-apis/bot/v2/hook/1234-5678",
			wantErr: false,
		},
		{
			name:    "feishu",
			url:     "https://open.feishu.cn/open-apis/bot/v2/hook/1234-5678",
			wantErr: false,
		},
		{
			name:    "http",
			url:     "http://open.larksuite.com/open-apis/bot/v2/hook/1234-5678",
			wantErr: true,
		},
		{
			name:    "unexpected host",
			url:     "https://example.com/open-apis/bot/v2/hook/1234-5678",
			wantErr: true,
		},
		{
			name:    "missing hook id",
			url:     "https://open.larksuite.com/open-apis/bot/v2/hook/",
			wantErr: true,
		},
		{
			name:    "unexpected path",
			url:     "https://open.larksuite.com/open-apis/im/v1/messages",
			wantErr: true,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := checkLarkWebhookURL(tt.url)
			if (err != nil) != tt.wantErr {
				t.Errorf("checkLarkWebhookURL(%q) error = %v, wantErr %v", tt.url, err, tt.wantErr)
			}
		})
	}
}

func TestMaskURL(t *testing.T) {
	masked := MaskURL("https://open.larksuite.com/open-apis/bot/v2/hook/1234567890abcdef")
	if masked == "https://open.larksuite.com/open-apis/bot/v2/hook/1234567890abcdef" {
		t.Fatal("expected hook id to be masked")
	}
	if masked[:len("https://open.larksuite.com/open-apis/bot/v2/hook/")] !=
		"https://open.larksuite.com/open-apis/bot/v2/hook/" {
		t.Fatalf("unexpected masked url: %s", masked)
	}
	if strings.Contains(masked, "1234567890abcdef") {
		t.Fatalf("masked url leaks hook id: %s", masked)
	}
}

func TestConvertDBLarkAlertSubscriberMasksCredentials(t *testing.T) {
	const (
		webhookURL = "https://open.larksuite.com/open-apis/bot/v2/hook/1234567890abcdef"
		secret     = "1234567890abcdef"
	)
	item, err := convertDBAlertSubscriber(db.AlertSubscriber{
		SubscriberType: string(entity.AlertSubscriberTypeLark),
		Name:           "lark-alerts",
		LarkWebhookUrl: webhookURL,
		LarkSecret:     secret,
	}, nil, true)
	if err != nil {
		t.Fatalf("convertDBAlertSubscriber returned error: %v", err)
	}
	if item.LarkWebhookUrl == webhookURL || strings.Contains(item.LarkWebhookUrl, "1234567890abcdef") {
		t.Fatalf("lark webhook url was not masked: %s", item.LarkWebhookUrl)
	}
	if item.LarkSecret == secret || strings.Contains(item.LarkSecret, secret) {
		t.Fatalf("lark secret was not masked: %s", item.LarkSecret)
	}
}
