package internal

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

	"github.com/golang-jwt/jwt/v5"
)

func TestSetSessionSetsCookieAndJWTClaims(t *testing.T) {
	origKey := sessionKey
	origSecure := cookieSecure
	sessionKey = []byte("session-test-key")
	cookieSecure = false
	t.Cleanup(func() {
		sessionKey = origKey
		cookieSecure = origSecure
	})

	rr := httptest.NewRecorder()
	if err := SetSession(rr, "brad", "jf-access"); err != nil {
		t.Fatalf("SetSession failed: %v", err)
	}

	res := rr.Result()
	defer res.Body.Close()
	cookies := res.Cookies()
	if len(cookies) != 1 {
		t.Fatalf("expected one cookie, got %d", len(cookies))
	}
	c := cookies[0]

	if c.Name != CookieName {
		t.Fatalf("unexpected cookie name %q", c.Name)
	}
	if c.HttpOnly != true {
		t.Fatalf("expected HttpOnly cookie")
	}
	if c.Path != "/" {
		t.Fatalf("unexpected cookie path %q", c.Path)
	}
	if c.Secure {
		t.Fatalf("expected insecure cookie when PEGASUS_COOKIE_INSECURE=1 behavior is enabled in test")
	}
	if c.SameSite != http.SameSiteLaxMode {
		t.Fatalf("unexpected SameSite value %v", c.SameSite)
	}

	tok, err := jwt.ParseWithClaims(c.Value, &Claims{}, func(_ *jwt.Token) (any, error) {
		return sessionKey, nil
	})
	if err != nil {
		t.Fatalf("cookie token failed to parse: %v", err)
	}
	claims, ok := tok.Claims.(*Claims)
	if !ok || !tok.Valid {
		t.Fatalf("parsed claims invalid")
	}
	if claims.Username != "brad" || claims.JFToken != "jf-access" {
		t.Fatalf("unexpected claims payload: %#v", claims)
	}
}

func TestClearSessionExpiresCookie(t *testing.T) {
	origSecure := cookieSecure
	cookieSecure = true
	t.Cleanup(func() {
		cookieSecure = origSecure
	})

	rr := httptest.NewRecorder()
	ClearSession(rr)

	res := rr.Result()
	defer res.Body.Close()
	cookies := res.Cookies()
	if len(cookies) != 1 {
		t.Fatalf("expected one cookie, got %d", len(cookies))
	}
	c := cookies[0]
	if c.Name != CookieName {
		t.Fatalf("unexpected cookie name %q", c.Name)
	}
	if c.Value != "" {
		t.Fatalf("expected cleared cookie value")
	}
	if c.MaxAge != -1 {
		t.Fatalf("expected MaxAge=-1, got %d", c.MaxAge)
	}
	if !c.Expires.IsZero() && c.Expires.Unix() != 0 {
		t.Fatalf("expected unix epoch expiry, got %v", c.Expires)
	}
	if !c.Secure {
		t.Fatalf("expected secure cookie")
	}
}

func TestSetSessionSigningError(t *testing.T) {
	origSign := signJWT
	defer func() { signJWT = origSign }()

	signJWT = func(*jwt.Token) (string, error) {
		return "", http.ErrNoCookie
	}

	rr := httptest.NewRecorder()
	if err := SetSession(rr, "brad", "jf"); err == nil {
		t.Fatalf("expected signing error")
	}
}
