package ucca

import (
	"testing"
)

func TestLoadCanonicalControls_ValidFile(t *testing.T) {
	idx, err := LoadCanonicalControls()
	if err != nil {
		t.Fatalf("Expected no error, got %v", err)
	}
	if idx == nil {
		t.Fatal("Expected non-nil index")
	}
	if len(idx.AllControls) != 10 {
		t.Errorf("Expected 10 controls, got %d", len(idx.AllControls))
	}
}

func TestCanonicalControlIndex_GetControl(t *testing.T) {
	idx, err := LoadCanonicalControls()
	if err != nil {
		t.Fatalf("Failed to load controls: %v", err)
	}

	tests := []struct {
		name     string
		id       string
		expected bool
	}{
		{"existing control AUTH-001", "AUTH-001", true},
		{"existing control NET-001", "NET-001", true},
		{"lowercase lookup", "auth-001", true},
		{"non-existing control", "FAKE-999", false},
		{"empty id", "", false},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			ctrl, ok := idx.GetControl(tt.id)
			if ok != tt.expected {
				t.Errorf("GetControl(%q): expected found=%v, got found=%v", tt.id, tt.expected, ok)
			}
			if ok && ctrl.ControlID == "" {
				t.Error("Control found but has empty ControlID")
			}
		})
	}
}

func TestCanonicalControlIndex_GetControlsByDomain(t *testing.T) {
	idx, err := LoadCanonicalControls()
	if err != nil {
		t.Fatalf("Failed to load controls: %v", err)
	}

	authControls := idx.GetControlsByDomain("AUTH")
	if len(authControls) != 2 {
		t.Errorf("Expected 2 AUTH controls, got %d", len(authControls))
	}

	netControls := idx.GetControlsByDomain("NET")
	if len(netControls) != 2 {
		t.Errorf("Expected 2 NET controls, got %d", len(netControls))
	}

	emptyControls := idx.GetControlsByDomain("NOPE")
	if len(emptyControls) != 0 {
		t.Errorf("Expected 0 controls for unknown domain, got %d", len(emptyControls))
	}
}

func TestCanonicalControlIndex_GetControlsBySeverity(t *testing.T) {
	idx, err := LoadCanonicalControls()
	if err != nil {
		t.Fatalf("Failed to load controls: %v", err)
	}

	highControls := idx.GetControlsBySeverity("high")
	if len(highControls) < 5 {
		t.Errorf("Expected at least 5 high-severity controls, got %d", len(highControls))
	}

	criticalControls := idx.GetControlsBySeverity("critical")
	if len(criticalControls) != 1 {
		t.Errorf("Expected 1 critical control, got %d", len(criticalControls))
	}
}

func TestCanonicalControlIndex_GetControlsByFramework(t *testing.T) {
	idx, err := LoadCanonicalControls()
	if err != nil {
		t.Fatalf("Failed to load controls: %v", err)
	}

	owaspControls := idx.GetControlsByFramework("OWASP ASVS")
	if len(owaspControls) == 0 {
		t.Error("Expected at least 1 control anchored to OWASP ASVS")
	}

	nistControls := idx.GetControlsByFramework("NIST SP 800-53")
	if len(nistControls) == 0 {
		t.Error("Expected at least 1 control anchored to NIST SP 800-53")
	}
}

func TestCanonicalControl_OpenAnchors(t *testing.T) {
	idx, err := LoadCanonicalControls()
	if err != nil {
		t.Fatalf("Failed to load controls: %v", err)
	}

	for _, ctrl := range idx.AllControls {
		if len(ctrl.OpenAnchors) == 0 {
			t.Errorf("Control %s has no open anchors — every control must have at least 1", ctrl.ControlID)
		}
		for i, anchor := range ctrl.OpenAnchors {
			if anchor.Framework == "" {
				t.Errorf("Control %s: open_anchor[%d] has empty framework", ctrl.ControlID, i)
			}
			if anchor.URL == "" {
				t.Errorf("Control %s: open_anchor[%d] has empty URL", ctrl.ControlID, i)
			}
		}
	}
}

func TestCanonicalControlIndex_ValidateControlID(t *testing.T) {
	idx, err := LoadCanonicalControls()
	if err != nil {
		t.Fatalf("Failed to load controls: %v", err)
	}

	if !idx.ValidateControlID("AUTH-001") {
		t.Error("Expected AUTH-001 to be valid")
	}
	if idx.ValidateControlID("FAKE-999") {
		t.Error("Expected FAKE-999 to be invalid")
	}
}

func TestCanonicalControlIndex_FrameworkMetadata(t *testing.T) {
	idx, err := LoadCanonicalControls()
	if err != nil {
		t.Fatalf("Failed to load controls: %v", err)
	}

	if idx.Framework.ID != "bp_security_v1" {
		t.Errorf("Expected framework ID 'bp_security_v1', got '%s'", idx.Framework.ID)
	}
	if len(idx.Domains) != 8 {
		t.Errorf("Expected 8 domains, got %d", len(idx.Domains))
	}
}
