package http

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

func TestBasicAuthMiddlewareDisabledWithoutPassword(t *testing.T) {
	req := httptest.NewRequest(http.MethodGet, "/api/tasks", nil)
	rec := httptest.NewRecorder()

	basicAuthMiddleware(AuthConfig{})(okHandler()).ServeHTTP(rec, req)

	if rec.Code != http.StatusOK {
		t.Fatalf("expected status %d, got %d", http.StatusOK, rec.Code)
	}
}

func TestBasicAuthMiddlewareRejectsMissingCredentials(t *testing.T) {
	req := httptest.NewRequest(http.MethodGet, "/api/tasks", nil)
	rec := httptest.NewRecorder()

	basicAuthMiddleware(AuthConfig{Username: "nomadcode", Password: "secret"})(okHandler()).ServeHTTP(rec, req)

	if rec.Code != http.StatusUnauthorized {
		t.Fatalf("expected status %d, got %d", http.StatusUnauthorized, rec.Code)
	}
	if got := rec.Header().Get("WWW-Authenticate"); got == "" {
		t.Fatal("expected WWW-Authenticate header")
	}
}

func TestBasicAuthMiddlewareAcceptsValidCredentials(t *testing.T) {
	req := httptest.NewRequest(http.MethodGet, "/api/tasks", nil)
	req.SetBasicAuth("nomadcode", "secret")
	rec := httptest.NewRecorder()

	basicAuthMiddleware(AuthConfig{Username: "nomadcode", Password: "secret"})(okHandler()).ServeHTTP(rec, req)

	if rec.Code != http.StatusOK {
		t.Fatalf("expected status %d, got %d", http.StatusOK, rec.Code)
	}
}

func TestRouterKeepsHealthzPublicAndProtectsAPI(t *testing.T) {
	protoSocketMock := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
	})

	router := NewRouter(NewHandler(nil, nil, nil, nil), nil, AuthConfig{
		Username: "nomadcode",
		Password: "secret",
	}, protoSocketMock, "/proto-socket")

	healthReq := httptest.NewRequest(http.MethodGet, "/healthz", nil)
	healthRec := httptest.NewRecorder()
	router.ServeHTTP(healthRec, healthReq)

	if healthRec.Code != http.StatusOK {
		t.Fatalf("expected /healthz status %d, got %d", http.StatusOK, healthRec.Code)
	}

	apiReq := httptest.NewRequest(http.MethodGet, "/api/tasks", nil)
	apiRec := httptest.NewRecorder()
	router.ServeHTTP(apiRec, apiReq)

	if apiRec.Code != http.StatusUnauthorized {
		t.Fatalf("expected /api/tasks status %d, got %d", http.StatusUnauthorized, apiRec.Code)
	}

	// Verify /proto-socket is protected
	wsReq := httptest.NewRequest(http.MethodGet, "/proto-socket", nil)
	wsRec := httptest.NewRecorder()
	router.ServeHTTP(wsRec, wsReq)

	if wsRec.Code != http.StatusUnauthorized {
		t.Fatalf("expected /proto-socket status %d, got %d", http.StatusUnauthorized, wsRec.Code)
	}

	// Verify /proto-socket works with valid credentials
	wsAuthReq := httptest.NewRequest(http.MethodGet, "/proto-socket", nil)
	wsAuthReq.SetBasicAuth("nomadcode", "secret")
	wsAuthRec := httptest.NewRecorder()
	router.ServeHTTP(wsAuthRec, wsAuthReq)

	if wsAuthRec.Code != http.StatusOK {
		t.Fatalf("expected /proto-socket with auth status %d, got %d", http.StatusOK, wsAuthRec.Code)
	}
}

func okHandler() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
	})
}
