package webagent

import (
	"net/http"
	"testing"

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

	"github.com/tidbcloud/AgentTeam/internal/api/testkit/httputil"
	"github.com/tidbcloud/AgentTeam/internal/store/agent"
)

// requireAlwaysOnBehaviorSettings asserts that every visible-reply-contract
// field is hard-pinned to true, regardless of any stored/requested false input.
func requireAlwaysOnBehaviorSettings(t *testing.T, body string) {
	t.Helper()
	require.Contains(t, body, `"accountVisibleReplyContractEnabled":true`)
	require.Contains(t, body, `"visibleReplyContractEnabled":true`)
	require.Contains(t, body, `"effectiveVisibleReplyContractEnabled":true`)
	require.NotContains(t, body, `false`)
}

func TestPOSTBehaviorSettingsUpdateAlias(t *testing.T) {
	type outcome struct {
		status int
		body   string
	}
	run := func(t *testing.T, method, path string, value any) outcome {
		t.Helper()
		fake := newFakeStore()
		runtime := &fakeRuntime{
			runningAgents: map[agentCall]bool{
				{MachineID: "mac_1", AgentID: "agt_1"}: true,
			},
		}
		router := newWebAgentRouter(Dependencies{AgentStore: fake, ReviewStore: fake, Runtime: runtime})
		resp := httputil.DoJSON(t, router, method, path, map[string]any{
			"visibleReplyContractEnabled": value,
		})
		return outcome{
			status: resp.Code,
			body:   resp.Body.String(),
		}
	}

	t.Run("POST success matches PATCH response and is always-on", func(t *testing.T) {
		patch := run(t, http.MethodPatch, "/api/v1/workspaces/wsp_1/agents/agt_1/behavior-settings", true)
		post := run(t, http.MethodPost, "/api/v1/workspaces/wsp_1/agents/agt_1/behavior-settings/update", true)
		require.Equal(t, patch, post)
		require.Equal(t, http.StatusOK, post.status)
		requireAlwaysOnBehaviorSettings(t, post.body)
	})

	t.Run("POST false is accepted but stays always-on", func(t *testing.T) {
		post := run(t, http.MethodPost, "/api/v1/workspaces/wsp_1/agents/agt_1/behavior-settings/update", false)
		require.Equal(t, http.StatusOK, post.status)
		requireAlwaysOnBehaviorSettings(t, post.body)
	})

	t.Run("POST null is accepted but stays always-on", func(t *testing.T) {
		post := run(t, http.MethodPost, "/api/v1/workspaces/wsp_1/agents/agt_1/behavior-settings/update", nil)
		require.Equal(t, http.StatusOK, post.status)
		requireAlwaysOnBehaviorSettings(t, post.body)
	})

	t.Run("POST behavior-settings/update without auth returns 401", func(t *testing.T) {
		router := gin.New()
		RegisterRoutes(router, Dependencies{})
		resp := httputil.DoJSON(t, router, http.MethodPost, "/api/v1/workspaces/wsp_1/agents/agt_1/behavior-settings/update", map[string]any{"visibleReplyContractEnabled": true})
		require.Equal(t, http.StatusUnauthorized, resp.Code)
	})
}

func TestGETBehaviorSettingsAlwaysOnDespiteStoredFalse(t *testing.T) {
	t.Parallel()

	fake := newFakeStore()
	// Simulate a historical DB row where every visible-reply-contract value is false.
	fake.behaviorSettings = agent.BehaviorSettings{
		WorkspaceID:                   "wsp_1",
		AgentID:                       "agt_1",
		AccountVisibleReplyContract:   false,
		VisibleReplyContractEnabled:   false,
		EffectiveVisibleReplyContract: false,
	}
	runtime := &fakeRuntime{
		runningAgents: map[agentCall]bool{
			{MachineID: "mac_1", AgentID: "agt_1"}: true,
		},
	}
	router := newWebAgentRouter(Dependencies{AgentStore: fake, ReviewStore: fake, Runtime: runtime})
	resp := httputil.DoJSON(t, router, http.MethodGet, "/api/v1/workspaces/wsp_1/agents/agt_1/behavior-settings", nil)

	require.Equal(t, http.StatusOK, resp.Code)
	requireAlwaysOnBehaviorSettings(t, resp.Body.String())
}
