package server

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

	"github.com/gin-gonic/gin"
	"github.com/google/uuid"

	"scrabble/backend/internal/session"
)

// TestRequireUserID checks that the middleware accepts a valid X-User-ID,
// exposes it through the request context, and rejects missing or malformed
// headers with 401.
func TestRequireUserID(t *testing.T) {
	gin.SetMode(gin.TestMode)

	var seen uuid.UUID
	var ok bool
	r := gin.New()
	r.Use(RequireUserID())
	r.GET("/x", func(c *gin.Context) {
		seen, ok = UserIDFromContext(c.Request.Context())
		c.String(http.StatusOK, "ok")
	})

	t.Run("valid", func(t *testing.T) {
		seen, ok = uuid.Nil, false
		id := uuid.New()
		req := httptest.NewRequest(http.MethodGet, "/x", nil)
		req.Header.Set("X-User-ID", id.String())
		rec := httptest.NewRecorder()
		r.ServeHTTP(rec, req)

		if rec.Code != http.StatusOK {
			t.Fatalf("status = %d, want 200", rec.Code)
		}
		if !ok || seen != id {
			t.Fatalf("context id = %s (ok=%v), want %s", seen, ok, id)
		}
	})

	t.Run("missing", func(t *testing.T) {
		rec := httptest.NewRecorder()
		r.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/x", nil))
		if rec.Code != http.StatusUnauthorized {
			t.Fatalf("status = %d, want 401", rec.Code)
		}
	})

	t.Run("malformed", func(t *testing.T) {
		req := httptest.NewRequest(http.MethodGet, "/x", nil)
		req.Header.Set("X-User-ID", "not-a-uuid")
		rec := httptest.NewRecorder()
		r.ServeHTTP(rec, req)
		if rec.Code != http.StatusUnauthorized {
			t.Fatalf("status = %d, want 401", rec.Code)
		}
	})
}

// TestPlatformContext checks that the middleware parses the gateway-injected
// X-Platform header into a trusted platform reachable via platform(c), treats an
// absent or blank-kind header as untrusted, and never rejects the request.
func TestPlatformContext(t *testing.T) {
	gin.SetMode(gin.TestMode)

	var seen session.Platform
	var ok bool
	r := gin.New()
	r.Use(platformContext())
	r.GET("/x", func(c *gin.Context) {
		seen, ok = platform(c)
		c.String(http.StatusOK, "ok")
	})

	for _, tc := range []struct {
		name      string
		header    string
		setHeader bool
		wantOK    bool
		want      session.Platform
	}{
		{"vk-ios", "vk/ios", true, true, session.Platform{Kind: session.PlatformKindVK, Subtype: session.SubtypeIOS}},
		{"telegram-no-subtype", "telegram", true, true, session.Platform{Kind: session.PlatformKindTelegram}},
		{"direct-web", "direct/web", true, true, session.Platform{Kind: session.PlatformKindDirect, Subtype: session.SubtypeWeb}},
		{"absent", "", false, false, session.Platform{}},
		{"empty", "", true, false, session.Platform{}},
		{"blank-kind", "/ios", true, false, session.Platform{}},
	} {
		t.Run(tc.name, func(t *testing.T) {
			seen, ok = session.Platform{}, false
			req := httptest.NewRequest(http.MethodGet, "/x", nil)
			if tc.setHeader {
				req.Header.Set("X-Platform", tc.header)
			}
			rec := httptest.NewRecorder()
			r.ServeHTTP(rec, req)

			if rec.Code != http.StatusOK {
				t.Fatalf("status = %d, want 200 (X-Platform never rejects)", rec.Code)
			}
			if ok != tc.wantOK || seen != tc.want {
				t.Fatalf("platform = %+v (ok=%v), want %+v (ok=%v)", seen, ok, tc.want, tc.wantOK)
			}
		})
	}
}
