package middleware

import (
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/seifghazi/claude-code-monitor/internal/config"
)

func TestAuthAllowsLocalhostBypass(t *testing.T) {
	called := false
	handler := Auth(config.AuthConfig{
		Enabled:              true,
		Token:                "secret",
		APIKeyHeader:         "X-API-Key",
		AllowLocalhostBypass: true,
	})(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		called = true
		w.WriteHeader(http.StatusOK)
	}))

	req := httptest.NewRequest(http.MethodPost, "http://example.local/v1/messages", nil)
	req.RemoteAddr = "127.0.0.1:45678"
	rr := httptest.NewRecorder()

	handler.ServeHTTP(rr, req)

	if !called {
		t.Fatal("expected localhost request to bypass auth")
	}
}

func TestAuthRejectsMissingCredentials(t *testing.T) {
	handler := Auth(config.AuthConfig{
		Enabled:      true,
		Token:        "secret",
		APIKeyHeader: "X-API-Key",
	})(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
	}))

	req := httptest.NewRequest(http.MethodPost, "http://example.local/v1/messages", nil)
	req.RemoteAddr = "10.1.2.3:45678"
	rr := httptest.NewRecorder()

	handler.ServeHTTP(rr, req)

	if rr.Code != http.StatusUnauthorized {
		t.Fatalf("expected 401, got %d", rr.Code)
	}
}

func TestAuthAcceptsBearerAndAPIKey(t *testing.T) {
	testCases := []struct {
		name   string
		setup  func(*http.Request)
		header string
	}{
		{
			name: "bearer",
			setup: func(r *http.Request) {
				r.Header.Set("Authorization", "Bearer secret")
			},
			header: "Authorization",
		},
		{
			name: "api-key",
			setup: func(r *http.Request) {
				r.Header.Set("X-API-Key", "secret")
			},
			header: "X-API-Key",
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			called := false
			handler := Auth(config.AuthConfig{
				Enabled:      true,
				Token:        "secret",
				APIKeyHeader: "X-API-Key",
			})(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
				called = true
				w.WriteHeader(http.StatusOK)
			}))

			req := httptest.NewRequest(http.MethodPost, "http://example.local/v1/messages", nil)
			req.RemoteAddr = "10.1.2.3:45678"
			tc.setup(req)
			rr := httptest.NewRecorder()

			handler.ServeHTTP(rr, req)

			if !called {
				t.Fatalf("expected %s auth to pass", tc.header)
			}
			if rr.Code != http.StatusOK {
				t.Fatalf("expected 200, got %d", rr.Code)
			}
		})
	}
}

func TestAuthSkipsPublicDiscoveryRoutesAndOptions(t *testing.T) {
	handler := Auth(config.AuthConfig{
		Enabled: true,
		Token:   "secret",
	})(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
	}))

	publicPaths := []string{"/health", "/openapi.json", "/openapi.yaml"}
	for _, path := range publicPaths {
		req := httptest.NewRequest(http.MethodGet, "http://example.local"+path, nil)
		rr := httptest.NewRecorder()
		handler.ServeHTTP(rr, req)
		if rr.Code != http.StatusOK {
			t.Fatalf("expected %s request to bypass auth, got %d", path, rr.Code)
		}
	}

	req := httptest.NewRequest(http.MethodOptions, "http://example.local/v1/messages", nil)
	rr := httptest.NewRecorder()
	handler.ServeHTTP(rr, req)
	if rr.Code != http.StatusOK {
		t.Fatalf("expected OPTIONS request to bypass auth, got %d", rr.Code)
	}
}
