package oauthroutes

import "testing"

// testRouteFamilyPrefix is a representative concrete route-family prefix the host
// supplies at runtime (the Salesforce data API). The kernel is prefix-blind; these
// tests pin behavior against an explicit Family.
const testRouteFamilyPrefix = "/services/data/"

func TestValidatePattern(t *testing.T) {
	f := NewFamily(testRouteFamilyPrefix)
	tests := []struct {
		name    string
		pattern string
		wantErr bool
	}{
		{"canonical version placeholder", "/services/data/:version/query", false},
		{"concrete lowercase version", "/services/data/v63.0/sobjects", false},
		{"non-family identity route", "/id/:orgId/:userId", false},
		{"non-family oauth route", "/services/oauth2/userinfo", false},
		{"base services data without version", "/services/data", false},
		{"malformed version segment", "/services/data/not-a-version/sobjects", true},
		{"uppercase version segment", "/services/data/V63.0/sobjects", true},
		{"version without minor", "/services/data/v63/sobjects", true},
		{"case-variant prefix fully capitalized", "/Services/Data/v63.0/query", true},
		{"case-variant prefix mixed", "/services/Data/v63.0/query", true},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := f.ValidatePattern(tt.pattern)
			if (err != nil) != tt.wantErr {
				t.Fatalf("Family.ValidatePattern(%q) err=%v, wantErr=%v", tt.pattern, err, tt.wantErr)
			}
		})
	}
}

func TestValidatePatterns(t *testing.T) {
	f := NewFamily(testRouteFamilyPrefix)
	if err := f.ValidatePatterns("/services/data/:version/query /id/:orgId/:userId"); err != nil {
		t.Fatalf("all-valid pattern set should pass: %v", err)
	}
	// A single malformed (case-variant prefix) pattern in the set must fail the
	// whole field, so readers drop the scope.
	if err := f.ValidatePatterns("/services/data/:version/query /Services/Data/v63.0/query"); err == nil {
		t.Fatal("a malformed case-variant prefix in the set must fail validation")
	}
}

func TestCanonicalPatternIsIdempotentAndCasePreserving(t *testing.T) {
	f := NewFamily(testRouteFamilyPrefix)
	// Real Gin request paths are lowercase; a concrete version collapses to the
	// shared key and re-collapsing is a no-op.
	if got := f.CanonicalPattern("/services/data/v63.0/sobjects"); got != "/services/data/:version/sobjects" {
		t.Fatalf("CanonicalPattern concrete version = %q", got)
	}
	if got := f.CanonicalPattern("/services/data/:version/sobjects"); got != "/services/data/:version/sobjects" {
		t.Fatalf("CanonicalPattern placeholder not idempotent = %q", got)
	}
	// A malformed version segment is left verbatim so it cannot alias the broad
	// ":version" key at runtime.
	if got := f.CanonicalPattern("/services/data/not-a-version/sobjects"); got != "/services/data/not-a-version/sobjects" {
		t.Fatalf("CanonicalPattern should leave malformed segment verbatim = %q", got)
	}
}
