package webagent

import (
	"net/http"
	"testing"

	"github.com/stretchr/testify/require"

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

func TestRuntimeHandlers(t *testing.T) {
	t.Run("start enables auto wake and ignores offline runtime", func(t *testing.T) {
		fake := newFakeStore()
		runtime := &fakeRuntime{startErr: runtimecontrol.ErrMachineOffline}
		router := newWebAgentRouter(Dependencies{AgentStore: fake, ReviewStore: fake, Runtime: runtime})

		resp := httputil.DoJSON(t, router, http.MethodPost, "/api/v1/workspaces/wsp_1/agents/agt_1/start", nil)
		require.Equal(t, http.StatusOK, resp.Code)
		require.Equal(t, "agt_1", fake.lastAutoWakeID)
		require.True(t, fake.lastAutoWake)
		require.Len(t, runtime.startCalls, 1)
	})

	t.Run("start delegates to runtime command port and preserves runtime conflict", func(t *testing.T) {
		fake := newFakeStore()
		commands := &fakeRuntimeCommands{startErr: runtimecontrol.ErrAgentStillRunning}
		router := newWebAgentRouter(Dependencies{AgentStore: fake, ReviewStore: fake, RuntimeCommands: commands})

		resp := httputil.DoJSON(t, router, http.MethodPost, "/api/v1/workspaces/wsp_1/agents/agt_1/start", nil)
		require.Equal(t, http.StatusConflict, resp.Code)
		require.Equal(t, "agt_1", commands.startAgentID)
		require.Empty(t, fake.lastAutoWakeID)
	})

	t.Run("start with agentteam proxy agent syncs machine catalog before runtime start", func(t *testing.T) {
		fake := newFakeStore()
		fake.autoWakeAgent = agent.AgentView{
			AgentID:   "agt_1",
			MachineID: "mach_1",
			LLMMode:   agent.AgentLLMModeAgentTeamProxy,
		}
		runtime := &fakeRuntime{}
		router := newWebAgentRouter(Dependencies{
			AgentStore:  fake,
			ReviewStore: fake,
			Runtime:     runtime,
		})

		resp := httputil.DoJSON(t, router, http.MethodPost, "/api/v1/workspaces/wsp_1/agents/agt_1/start", nil)
		require.Equal(t, http.StatusOK, resp.Code)
		require.Equal(t, []string{"mach_1"}, runtime.syncMachineCalls)
		require.Len(t, runtime.startCalls, 1)
	})

	t.Run("stop disables auto wake and emits stopping for active agent", func(t *testing.T) {
		fake := newFakeStore()
		fake.autoWakeAgent = agent.AgentView{AgentID: "agt_1", MachineID: "mach_1", Status: "inactive"}
		runtime := &fakeRuntime{
			runningAgents: map[agentCall]bool{{MachineID: "mach_1", AgentID: "agt_1"}: true},
		}
		realtime := &fakeRealtime{}
		router := newWebAgentRouter(Dependencies{AgentStore: fake, ReviewStore: fake, Runtime: runtime, Realtime: realtime})

		resp := httputil.DoJSON(t, router, http.MethodPost, "/api/v1/workspaces/wsp_1/agents/agt_1/stop", nil)
		require.Equal(t, http.StatusOK, resp.Code)
		require.False(t, fake.lastAutoWake)
		require.Equal(t, []activityCall{{WorkspaceID: "wsp_1", OwnerUserID: "usr_1", AgentID: "agt_1", Status: "stopping"}}, realtime.activityCalls)
	})

	t.Run("reset clears workspace, recovery points, and runtime token", func(t *testing.T) {
		fake := newFakeStore()
		fake.deletedRecovery = []rewind.MessageRecoveryPoint{{MessageID: "msg_1", AgentID: "agt_1"}}
		runtime := &fakeRuntime{}
		router := newWebAgentRouter(Dependencies{AgentStore: fake, ReviewStore: fake, Runtime: runtime})

		resp := httputil.DoJSON(t, router, http.MethodPost, "/api/v1/workspaces/wsp_1/agents/agt_1/reset", map[string]any{"clearWorkspace": true})
		require.Equal(t, http.StatusOK, resp.Code)
		require.Len(t, runtime.resetSessionCalls, 1)
		require.Len(t, runtime.resetCalls, 1)
		require.Len(t, runtime.gcCalls, 1)
		require.Equal(t, "agt_1", fake.lastClearSession)
	})

	t.Run("reset with clearWorkspace requires runtime", func(t *testing.T) {
		fake := newFakeStore()
		router := newWebAgentRouter(Dependencies{AgentStore: fake, ReviewStore: fake})

		resp := httputil.DoJSON(t, router, http.MethodPost, "/api/v1/workspaces/wsp_1/agents/agt_1/reset", map[string]any{"clearWorkspace": true})
		require.Equal(t, http.StatusServiceUnavailable, resp.Code)
	})
}
