package auth

import (
	"context"
	"net/http"
	"net/http/httptest"
	"testing"
	"time"
)

// BenchmarkAuthMiddleware benchmarks the authentication middleware overhead.
func BenchmarkAuthMiddleware(b *testing.B) {
	// Create a mock API key
	apiKey := &APIKey{
		ID:        "test-key-id",
		Name:      "benchmark-key",
		KeyPrefix: "rdev",
		Scopes:    []Scope{ScopeProjectsExecute, ScopeProjectsRead},
		CreatedAt: time.Now(),
	}

	// Simple handler that just writes OK
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
	})

	// Wrap with a mock middleware that simulates auth without DB
	middleware := func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			// Simulate auth header parsing
			key := r.Header.Get(HeaderAPIKey)
			if key == "" {
				auth := r.Header.Get("Authorization")
				if len(auth) > 7 && auth[:7] == "Bearer " {
					key = auth[7:]
				}
			}

			if key == "" {
				w.WriteHeader(http.StatusUnauthorized)
				return
			}

			// Simulate key validation (without DB)
			if key != "valid-key" {
				w.WriteHeader(http.StatusUnauthorized)
				return
			}

			// Add key to context
			ctx := context.WithValue(r.Context(), contextKeyAPIKey, apiKey)
			next.ServeHTTP(w, r.WithContext(ctx))
		})
	}

	wrappedHandler := middleware(handler)

	b.ResetTimer()
	b.ReportAllocs()

	for i := 0; i < b.N; i++ {
		req := httptest.NewRequest("GET", "/projects", nil)
		req.Header.Set(HeaderAPIKey, "valid-key")
		rec := httptest.NewRecorder()
		wrappedHandler.ServeHTTP(rec, req)
	}
}

// BenchmarkAuthMiddleware_Bearer benchmarks auth with Bearer token.
func BenchmarkAuthMiddleware_Bearer(b *testing.B) {
	apiKey := &APIKey{
		ID:        "test-key-id",
		Name:      "benchmark-key",
		KeyPrefix: "rdev",
		Scopes:    []Scope{ScopeProjectsExecute, ScopeProjectsRead},
		CreatedAt: time.Now(),
	}

	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
	})

	middleware := func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			key := r.Header.Get(HeaderAPIKey)
			if key == "" {
				auth := r.Header.Get("Authorization")
				if len(auth) > 7 && auth[:7] == "Bearer " {
					key = auth[7:]
				}
			}

			if key == "" || key != "valid-key" {
				w.WriteHeader(http.StatusUnauthorized)
				return
			}

			ctx := context.WithValue(r.Context(), contextKeyAPIKey, apiKey)
			next.ServeHTTP(w, r.WithContext(ctx))
		})
	}

	wrappedHandler := middleware(handler)

	b.ResetTimer()
	b.ReportAllocs()

	for i := 0; i < b.N; i++ {
		req := httptest.NewRequest("GET", "/projects", nil)
		req.Header.Set("Authorization", "Bearer valid-key")
		rec := httptest.NewRecorder()
		wrappedHandler.ServeHTTP(rec, req)
	}
}

// BenchmarkRequireScope benchmarks the scope checking middleware.
func BenchmarkRequireScope(b *testing.B) {
	apiKey := &APIKey{
		ID:        "test-key-id",
		Name:      "benchmark-key",
		KeyPrefix: "rdev",
		Scopes:    []Scope{ScopeProjectsExecute, ScopeProjectsRead},
		CreatedAt: time.Now(),
	}

	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
	})

	scopeMiddleware := RequireScope(ScopeProjectsExecute)
	wrappedHandler := scopeMiddleware(handler)

	b.ResetTimer()
	b.ReportAllocs()

	for i := 0; i < b.N; i++ {
		req := httptest.NewRequest("POST", "/projects/test/claude", nil)
		// Pre-set the API key in context
		ctx := context.WithValue(req.Context(), contextKeyAPIKey, apiKey)
		req = req.WithContext(ctx)
		rec := httptest.NewRecorder()
		wrappedHandler.ServeHTTP(rec, req)
	}
}

// BenchmarkGetClientIP benchmarks IP extraction from requests.
func BenchmarkGetClientIP(b *testing.B) {
	req := httptest.NewRequest("GET", "/", nil)
	req.RemoteAddr = "192.168.1.100:12345"

	b.ResetTimer()
	b.ReportAllocs()

	for i := 0; i < b.N; i++ {
		_ = getClientIP(req)
	}
}

// BenchmarkGetClientIP_XForwardedFor benchmarks IP extraction with X-Forwarded-For.
func BenchmarkGetClientIP_XForwardedFor(b *testing.B) {
	req := httptest.NewRequest("GET", "/", nil)
	req.Header.Set("X-Forwarded-For", "10.0.0.1, 192.168.1.1, 172.16.0.1")
	req.RemoteAddr = "127.0.0.1:12345"

	b.ResetTimer()
	b.ReportAllocs()

	for i := 0; i < b.N; i++ {
		_ = getClientIP(req)
	}
}

// BenchmarkGetClientIP_IPv6 benchmarks IP extraction for IPv6.
func BenchmarkGetClientIP_IPv6(b *testing.B) {
	req := httptest.NewRequest("GET", "/", nil)
	req.RemoteAddr = "[2001:db8::1]:12345"

	b.ResetTimer()
	b.ReportAllocs()

	for i := 0; i < b.N; i++ {
		_ = getClientIP(req)
	}
}

// BenchmarkIPAllowlistCheck benchmarks the IP allowlist checking.
func BenchmarkIPAllowlistCheck(b *testing.B) {
	apiKey := &APIKey{
		ID:         "test-key-id",
		Name:       "benchmark-key",
		KeyPrefix:  "rdev",
		Scopes:     []Scope{ScopeProjectsExecute},
		AllowedIPs: []string{"192.168.1.0/24", "10.0.0.0/8", "172.16.0.0/12"},
		CreatedAt:  time.Now(),
	}

	b.ResetTimer()
	b.ReportAllocs()

	for i := 0; i < b.N; i++ {
		_ = apiKey.IsIPAllowed("192.168.1.100")
	}
}

// BenchmarkIPAllowlistCheck_NoAllowlist benchmarks IP check when no allowlist configured.
func BenchmarkIPAllowlistCheck_NoAllowlist(b *testing.B) {
	apiKey := &APIKey{
		ID:        "test-key-id",
		Name:      "benchmark-key",
		KeyPrefix: "rdev",
		Scopes:    []Scope{ScopeProjectsExecute},
		CreatedAt: time.Now(),
	}

	b.ResetTimer()
	b.ReportAllocs()

	for i := 0; i < b.N; i++ {
		_ = apiKey.IsIPAllowed("192.168.1.100")
	}
}

// BenchmarkHealthEndpointSkip benchmarks the path-skip logic for health endpoints.
func BenchmarkHealthEndpointSkip(b *testing.B) {
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
	})

	// Simulate the skip check in middleware
	middleware := func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			path := r.URL.Path
			if path == "/health" || path == "/ready" || path == "/metrics" {
				next.ServeHTTP(w, r)
				return
			}
			// Would do auth here
			next.ServeHTTP(w, r)
		})
	}

	wrappedHandler := middleware(handler)

	b.ResetTimer()
	b.ReportAllocs()

	for i := 0; i < b.N; i++ {
		req := httptest.NewRequest("GET", "/health", nil)
		rec := httptest.NewRecorder()
		wrappedHandler.ServeHTTP(rec, req)
	}
}

// BenchmarkConcurrentAuth benchmarks concurrent auth middleware calls.
func BenchmarkConcurrentAuth(b *testing.B) {
	apiKey := &APIKey{
		ID:        "test-key-id",
		Name:      "benchmark-key",
		KeyPrefix: "rdev",
		Scopes:    []Scope{ScopeProjectsExecute, ScopeProjectsRead},
		CreatedAt: time.Now(),
	}

	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
	})

	middleware := func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			key := r.Header.Get(HeaderAPIKey)
			if key == "" || key != "valid-key" {
				w.WriteHeader(http.StatusUnauthorized)
				return
			}
			ctx := context.WithValue(r.Context(), contextKeyAPIKey, apiKey)
			next.ServeHTTP(w, r.WithContext(ctx))
		})
	}

	wrappedHandler := middleware(handler)

	b.ResetTimer()
	b.ReportAllocs()

	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			req := httptest.NewRequest("GET", "/projects", nil)
			req.Header.Set(HeaderAPIKey, "valid-key")
			rec := httptest.NewRecorder()
			wrappedHandler.ServeHTTP(rec, req)
		}
	})
}
