package handler

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

	"github.com/gin-gonic/gin"
	"github.com/stretchr/testify/require"

	"security-center-backend/internal/middleware"
	"security-center-backend/internal/service/jwt"
)

// newCurrentActorTestContext 构造带请求上下文的 gin.Context;
// agent=true 时模拟 AgentAuth 成功分支, 把 claims 注入请求上下文 (plan 002 §3.2)。
func newCurrentActorTestContext(t *testing.T, claims *jwt.Claims, agent bool) *gin.Context {
	t.Helper()
	gin.SetMode(gin.TestMode)
	rec := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(rec)
	req := httptest.NewRequest(http.MethodPost, "/api/v1/vulnerabilities/vul-26-0001/comments", nil)
	if agent {
		req = req.WithContext(middleware.WithAgentClaims(req.Context(), claims))
	}
	c.Request = req
	if claims != nil {
		c.Set("current_user", claims)
	}
	return c
}

func TestCurrentActorAgentAttribution(t *testing.T) {
	t.Run("agent with name is attributed to the key name", func(t *testing.T) {
		claims := &jwt.Claims{
			UserID:          7,
			ActorType:       "agent",
			AgentID:         42,
			AgentName:       "vuln-scanner-key",
			DelegatedUserID: 7,
		}
		c := newCurrentActorTestContext(t, claims, true)

		name, actorID := currentActor(c)

		require.Equal(t, "vuln-scanner-key", name)
		require.NotNil(t, actorID)
		require.Equal(t, uint64(7), *actorID)
	})

	t.Run("agent without name falls back to agent id", func(t *testing.T) {
		claims := &jwt.Claims{
			UserID:    7,
			ActorType: "agent",
			AgentID:   42,
		}
		c := newCurrentActorTestContext(t, claims, true)

		name, actorID := currentActor(c)

		require.Equal(t, "agent:42", name)
		require.NotNil(t, actorID)
		require.Equal(t, uint64(7), *actorID)
	})
}

func TestCurrentActorHumanAttributionUnchanged(t *testing.T) {
	t.Run("human request returns email", func(t *testing.T) {
		claims := &jwt.Claims{UserID: 3, Email: "human@example.com"}
		c := newCurrentActorTestContext(t, claims, false)

		name, actorID := currentActor(c)

		require.Equal(t, "human@example.com", name)
		require.NotNil(t, actorID)
		require.Equal(t, uint64(3), *actorID)
	})

	t.Run("missing current user falls back to system", func(t *testing.T) {
		c := newCurrentActorTestContext(t, nil, false)

		name, actorID := currentActor(c)

		require.Equal(t, "System", name)
		require.Nil(t, actorID)
	})
}
