package spindle

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

	"tangled.org/core/idresolver"
	"tangled.org/core/spindle/config"
)

func TestAdminRouterMountedOnlyWhenConfigured(t *testing.T) {
	tests := []struct {
		name     string
		password string
		want     int
	}{
		// mounted: rejects the unauthenticated request instead of 404ing
		{"configured", "s3cret", http.StatusUnauthorized},
		{"unset password", "", http.StatusNotFound},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			s := &Spindle{
				l:   slog.Default(),
				res: idresolver.DefaultResolver("https://plc.test"),
				cfg: &config.Config{Server: config.Server{
					AdminPassword: tt.password,
					Hostname:      "spindle.test",
				}},
			}

			req := httptest.NewRequest(http.MethodPost, "/admin/member/allow", nil)
			w := httptest.NewRecorder()
			s.Router().ServeHTTP(w, req)

			if w.Code != tt.want {
				t.Errorf("status = %d, want %d", w.Code, tt.want)
			}
		})
	}
}

func TestAdminMiddleware(t *testing.T) {
	tests := []struct {
		name       string
		configured string
		user, pass string
		basicAuth  bool
		want       int
	}{
		{"correct password", "s3cret", "admin", "s3cret", true, http.StatusOK},
		{"wrong password", "s3cret", "admin", "nope", true, http.StatusUnauthorized},
		{"wrong user", "s3cret", "root", "s3cret", true, http.StatusUnauthorized},
		{"no credentials", "s3cret", "", "", false, http.StatusUnauthorized},
		// Router() skips the mount when the password is unset, but keep the middleware
		// fail-closed too - an empty password must not authenticate anyone.
		{"unset password", "", "admin", "", true, http.StatusUnauthorized},
		{"unset password, no credentials", "", "", "", false, http.StatusUnauthorized},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			s := &Spindle{cfg: &config.Config{
				Server: config.Server{AdminPassword: tt.configured},
			}}

			req := httptest.NewRequest(http.MethodPost, "/admin/member/allow", nil)
			if tt.basicAuth {
				req.SetBasicAuth(tt.user, tt.pass)
			}
			w := httptest.NewRecorder()

			s.adminMiddleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
				w.WriteHeader(http.StatusOK)
			})).ServeHTTP(w, req)

			if w.Code != tt.want {
				t.Errorf("status = %d, want %d", w.Code, tt.want)
			}
		})
	}
}
