package webhook

import (
	"strings"
	"testing"

	"github.com/gitlink-org/gitlink-cli/shortcuts/common"
)

func TestIsEventSupported(t *testing.T) {
	tests := []struct {
		name     string
		event    string
		expected bool
	}{
		{
			name:     "supported event - push",
			event:    "push",
			expected: true,
		},
		{
			name:     "supported event - pull_request",
			event:    "pull_request",
			expected: true,
		},
		{
			name:     "supported event - issue",
			event:    "issue",
			expected: true,
		},
		{
			name:     "unsupported event",
			event:    "unsupported_event",
			expected: false,
		},
		{
			name:     "empty event",
			event:    "",
			expected: false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := isEventSupported(tt.event)
			if result != tt.expected {
				t.Errorf("isEventSupported(%q) = %v, want %v", tt.event, result, tt.expected)
			}
		})
	}
}

func TestParseEvents(t *testing.T) {
	tests := []struct {
		name     string
		events   string
		expected []string
	}{
		{
			name:     "single event",
			events:   "push",
			expected: []string{"push"},
		},
		{
			name:     "multiple events",
			events:   "push,pull_request,issue",
			expected: []string{"push", "pull_request", "issue"},
		},
		{
			name:     "events with spaces",
			events:   "push, pull_request, issue",
			expected: []string{"push", "pull_request", "issue"},
		},
		{
			name:     "mixed valid and invalid events",
			events:   "push,invalid_event,pull_request",
			expected: []string{"push", "pull_request"},
		},
		{
			name:     "empty string - default to push",
			events:   "",
			expected: []string{"push"},
		},
		{
			name:     "all invalid events",
			events:   "invalid1,invalid2",
			expected: []string{},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := parseEvents(tt.events)
			if len(result) != len(tt.expected) {
				t.Errorf("parseEvents(%q) returned %d events, want %d", tt.events, len(result), len(tt.expected))
				return
			}
			for i, event := range result {
				if event != tt.expected[i] {
					t.Errorf("parseEvents(%q)[%d] = %q, want %q", tt.events, i, event, tt.expected[i])
				}
			}
		})
	}
}

func TestGetEventDescription(t *testing.T) {
	tests := []struct {
		name     string
		event    string
		expected string
	}{
		{
			name:     "push event description",
			event:    "push",
			expected: "Code push events",
		},
		{
			name:     "pull_request event description",
			event:    "pull_request",
			expected: "Pull request events",
		},
		{
			name:     "issue event description",
			event:    "issue",
			expected: "Issue events",
		},
		{
			name:     "unknown event description",
			event:    "unknown_event",
			expected: "Custom event",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := getEventDescription(tt.event)
			if result != tt.expected {
				t.Errorf("getEventDescription(%q) = %q, want %q", tt.event, result, tt.expected)
			}
		})
	}
}

func TestShortcuts(t *testing.T) {
	shortcuts := Shortcuts()

	if len(shortcuts) == 0 {
		t.Fatal("Shortcuts() returned empty slice")
	}

	// 验证所有必需的shortcuts都存在
	expectedShortcuts := []string{
		"list", "create", "update", "delete", "test", "info", "events",
	}

	shortcutNames := make(map[string]bool)
	for _, sc := range shortcuts {
		shortcutNames[sc.Name] = true
	}

	for _, expected := range expectedShortcuts {
		if !shortcutNames[expected] {
			t.Errorf("Missing shortcut: %s", expected)
		}
	}

	// 验证每个shortcut的基本属性
	for _, sc := range shortcuts {
		if sc.Name == "" {
			t.Error("Shortcut has empty Name")
		}
		if sc.Description == "" {
			t.Errorf("Shortcut %q has empty Description", sc.Name)
		}
		if sc.Run == nil {
			t.Errorf("Shortcut %q has nil Run function", sc.Name)
		}
	}
}

// TestWebhookEventsList tests the events shortcut to ensure it returns valid event information
func TestWebhookEventsList(t *testing.T) {
	shortcuts := Shortcuts()
	var eventsShortcut *common.Shortcut
	for _, sc := range shortcuts {
		if sc.Name == "events" {
			eventsShortcut = sc
			break
		}
	}

	if eventsShortcut == nil {
		t.Fatal("Events shortcut not found")
	}

	// 验证所有支持的事件都有描述
	for _, event := range supportedEvents {
		desc := getEventDescription(event)
		if desc == "" {
			t.Errorf("Event %q has empty description", event)
		}
	}
}

// TestEventValidationIntegration tests event validation in an integrated manner
func TestEventValidationIntegration(t *testing.T) {
	// 测试所有支持的事件都能被正确识别
	for _, event := range supportedEvents {
		if !isEventSupported(event) {
			t.Errorf("Supported event %q is not recognized by isEventSupported", event)
		}
		// 确保描述不为空
		desc := getEventDescription(event)
		if desc == "" {
			t.Errorf("Event %q has empty description", event)
		}
	}

	// 测试解析包含所有支持的事件字符串
	allEvents := strings.Join(supportedEvents, ",")
	parsed := parseEvents(allEvents)
	if len(parsed) != len(supportedEvents) {
		t.Errorf("Parsing all events returned %d results, expected %d", len(parsed), len(supportedEvents))
	}
}

// BenchmarkParseEvents benchmarks the event parsing function
func BenchmarkParseEvents(b *testing.B) {
	eventsStr := "push,pull_request,issue,issue_assign,issue_comment,pull_request_assign,pull_request_comment"
	for i := 0; i < b.N; i++ {
		parseEvents(eventsStr)
	}
}

// BenchmarkIsEventSupported benchmarks the event validation function
func BenchmarkIsEventSupported(b *testing.B) {
	for i := 0; i < b.N; i++ {
		for _, event := range supportedEvents {
			isEventSupported(event)
		}
	}
}
