package routing

import (
	"os"
	"testing"
)

func getKBPath() string {
	// Try direct name (when running from this directory)
	if _, err := os.Stat("activity_knowledge_base.json"); err == nil {
		return "activity_knowledge_base.json"
	}
	// Try relative path
	if _, err := os.Stat("./internal/routing/activity_knowledge_base.json"); err == nil {
		return "./internal/routing/activity_knowledge_base.json"
	}
	return ""
}

func TestLoadKnowledgeBase(t *testing.T) {
	kbPath := getKBPath()
	if kbPath == "" {
		t.Skip("Knowledge base file not found, skipping test")
	}

	kb, err := LoadKnowledgeBase(kbPath)
	if err != nil {
		t.Fatalf("Failed to load knowledge base: %v", err)
	}

	if kb == nil {
		t.Error("Knowledge base is nil")
	}

	if kb.Version == "" {
		t.Error("Knowledge base version is empty")
	}

	if len(kb.Activities) == 0 {
		t.Error("Knowledge base has no activities")
	}

	if len(kb.byName) != len(kb.Activities) {
		t.Errorf("Index size (%d) doesn't match activities (%d)", len(kb.byName), len(kb.Activities))
	}
}

func TestGetActivity(t *testing.T) {
	kbPath := getKBPath()
	if kbPath == "" {
		t.Skip("Knowledge base file not found, skipping test")
	}

	kb, err := LoadKnowledgeBase(kbPath)
	if err != nil {
		t.Fatalf("Failed to load knowledge base: %v", err)
	}

	activity := kb.GetActivity("CloneRepoActivity")
	if activity == nil {
		t.Error("CloneRepoActivity not found")
	} else {
		if activity.Name != "CloneRepoActivity" {
			t.Errorf("Activity name mismatch: %s", activity.Name)
		}
		if activity.Description == "" {
			t.Error("Activity description is empty")
		}
	}

	missing := kb.GetActivity("NonExistentActivity")
	if missing != nil {
		t.Error("NonExistentActivity should be nil")
	}
}

func TestHasActivity(t *testing.T) {
	kbPath := getKBPath()
	if kbPath == "" {
		t.Skip("Knowledge base file not found, skipping test")
	}

	kb, err := LoadKnowledgeBase(kbPath)
	if err != nil {
		t.Fatalf("Failed to load knowledge base: %v", err)
	}

	if !kb.HasActivity("CloneRepoActivity") {
		t.Error("CloneRepoActivity should exist")
	}

	if kb.HasActivity("NonExistentActivity") {
		t.Error("NonExistentActivity should not exist")
	}
}

func TestListActivities(t *testing.T) {
	kbPath := getKBPath()
	if kbPath == "" {
		t.Skip("Knowledge base file not found, skipping test")
	}

	kb, err := LoadKnowledgeBase(kbPath)
	if err != nil {
		t.Fatalf("Failed to load knowledge base: %v", err)
	}

	activities := kb.ListActivities()
	if len(activities) == 0 {
		t.Error("ListActivities returned empty list")
	}

	for _, activity := range activities {
		if activity.Name == "" {
			t.Error("Activity name is empty")
		}
	}
}

func TestListActivitiesByCategory(t *testing.T) {
	kbPath := getKBPath()
	if kbPath == "" {
		t.Skip("Knowledge base file not found, skipping test")
	}

	kb, err := LoadKnowledgeBase(kbPath)
	if err != nil {
		t.Fatalf("Failed to load knowledge base: %v", err)
	}

	repoActivities := kb.ListActivitiesByCategory("repository")
	if len(repoActivities) == 0 {
		t.Error("No repository activities found")
	}

	for _, activity := range repoActivities {
		if activity.Category != "repository" {
			t.Errorf("Activity %s has wrong category: %s", activity.Name, activity.Category)
		}
	}

	unknown := kb.ListActivitiesByCategory("unknown")
	if len(unknown) != 0 {
		t.Error("Unknown category should return empty list")
	}
}

func TestGetActivityNames(t *testing.T) {
	kbPath := getKBPath()
	if kbPath == "" {
		t.Skip("Knowledge base file not found, skipping test")
	}

	kb, err := LoadKnowledgeBase(kbPath)
	if err != nil {
		t.Fatalf("Failed to load knowledge base: %v", err)
	}

	names := kb.GetActivityNames()
	if len(names) == 0 {
		t.Error("GetActivityNames returned empty list")
	}

	found := false
	for _, name := range names {
		if name == "CloneRepoActivity" {
			found = true
			break
		}
	}
	if !found {
		t.Error("CloneRepoActivity not found in activity names")
	}
}

func TestGetDependencies(t *testing.T) {
	kbPath := getKBPath()
	if kbPath == "" {
		t.Skip("Knowledge base file not found, skipping test")
	}

	kb, err := LoadKnowledgeBase(kbPath)
	if err != nil {
		t.Fatalf("Failed to load knowledge base: %v", err)
	}

	deps := kb.GetDependencies("AnalyzeCodeActivity")
	if len(deps) == 0 {
		t.Error("AnalyzeCodeActivity should have dependencies")
	}

	found := false
	for _, dep := range deps {
		if dep == "CloneRepoActivity" {
			found = true
			break
		}
	}
	if !found {
		t.Error("CloneRepoActivity should be a dependency of AnalyzeCodeActivity")
	}

	noDeps := kb.GetDependencies("CloneRepoActivity")
	if len(noDeps) != 0 {
		t.Error("CloneRepoActivity should have no dependencies")
	}
}

func TestGetTimeout(t *testing.T) {
	kbPath := getKBPath()
	if kbPath == "" {
		t.Skip("Knowledge base file not found, skipping test")
	}

	kb, err := LoadKnowledgeBase(kbPath)
	if err != nil {
		t.Fatalf("Failed to load knowledge base: %v", err)
	}

	timeout := kb.GetTimeoutForActivity("CloneRepoActivity")
	if timeout == "" {
		t.Error("Timeout should not be empty")
	}

	defaultTimeout := kb.GetTimeoutForActivity("NonExistent")
	if defaultTimeout != "5m" {
		t.Errorf("Default timeout should be 5m, got %s", defaultTimeout)
	}
}

func TestGetRetryPolicy(t *testing.T) {
	kbPath := getKBPath()
	if kbPath == "" {
		t.Skip("Knowledge base file not found, skipping test")
	}

	kb, err := LoadKnowledgeBase(kbPath)
	if err != nil {
		t.Fatalf("Failed to load knowledge base: %v", err)
	}

	policy := kb.GetRetryPolicyForActivity("AnalyzeCodeActivity")
	if policy == nil {
		t.Error("Retry policy should not be nil")
	} else {
		if policy.MaxAttempts < 2 {
			t.Errorf("Flaky activity should have multiple retries, got %d", policy.MaxAttempts)
		}
		if policy.BackoffRate == 0 {
			t.Error("Backoff rate should be set")
		}
	}

	stablePolicy := kb.GetRetryPolicyForActivity("CloneRepoActivity")
	if stablePolicy == nil {
		t.Error("Retry policy should not be nil")
	}
}

func TestIsFlaky(t *testing.T) {
	kbPath := getKBPath()
	if kbPath == "" {
		t.Skip("Knowledge base file not found, skipping test")
	}

	kb, err := LoadKnowledgeBase(kbPath)
	if err != nil {
		t.Fatalf("Failed to load knowledge base: %v", err)
	}

	if !kb.IsFlaky("AnalyzeCodeActivity") {
		t.Error("AnalyzeCodeActivity should be marked as flaky")
	}

	if kb.IsFlaky("CloneRepoActivity") {
		t.Error("CloneRepoActivity should not be marked as flaky")
	}
}

func TestGetNotes(t *testing.T) {
	kbPath := getKBPath()
	if kbPath == "" {
		t.Skip("Knowledge base file not found, skipping test")
	}

	kb, err := LoadKnowledgeBase(kbPath)
	if err != nil {
		t.Fatalf("Failed to load knowledge base: %v", err)
	}

	notes := kb.GetNotes("AnalyzeCodeActivity")
	if notes == "" {
		t.Error("Notes should not be empty")
	}

	missingNotes := kb.GetNotes("NonExistent")
	if missingNotes != "" {
		t.Error("Non-existent activity should have empty notes")
	}
}

func TestValidate(t *testing.T) {
	kbPath := getKBPath()
	if kbPath == "" {
		t.Skip("Knowledge base file not found, skipping test")
	}

	kb, err := LoadKnowledgeBase(kbPath)
	if err != nil {
		t.Fatalf("Failed to load knowledge base: %v", err)
	}

	if err := kb.Validate(); err != nil {
		t.Fatalf("Knowledge base validation failed: %v", err)
	}
}

func TestString(t *testing.T) {
	kbPath := getKBPath()
	if kbPath == "" {
		t.Skip("Knowledge base file not found, skipping test")
	}

	kb, err := LoadKnowledgeBase(kbPath)
	if err != nil {
		t.Fatalf("Failed to load knowledge base: %v", err)
	}

	str := kb.String()
	if str == "" {
		t.Error("String() returned empty string")
	}

	if !contains(str, "KnowledgeBase") {
		t.Error("String should contain 'KnowledgeBase'")
	}
}

func TestPrintSummary(t *testing.T) {
	kbPath := getKBPath()
	if kbPath == "" {
		t.Skip("Knowledge base file not found, skipping test")
	}

	kb, err := LoadKnowledgeBase(kbPath)
	if err != nil {
		t.Fatalf("Failed to load knowledge base: %v", err)
	}

	summary := kb.PrintSummary()
	if summary == "" {
		t.Error("PrintSummary() returned empty string")
	}

	if !contains(summary, "Activity Knowledge Base") {
		t.Error("Summary should contain 'Activity Knowledge Base'")
	}

	if !contains(summary, "CloneRepoActivity") {
		t.Error("Summary should list activities")
	}
}

func contains(str, substr string) bool {
	for i := 0; i < len(str)-len(substr)+1; i++ {
		if str[i:i+len(substr)] == substr {
			return true
		}
	}
	return false
}
