package webagent

import (
	"encoding/json"
	"net/http"
	"testing"

	"github.com/stretchr/testify/require"

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

func TestRuntimeSnapshotHandler(t *testing.T) {
	t.Run("lists bounded runtime snapshots for requested agent ids", func(t *testing.T) {
		fake := newFakeStore()
		fake.runtimeSnapshots = []agent.AgentRuntimeSnapshot{
			{
				AgentID:         "agt_1",
				MachineID:       "mac_1",
				CanManage:       true,
				MachineStatus:   "offline",
				AutoWakeEnabled: true,
				Status:          "inactive",
				Activity:        "offline",
			},
		}
		runtime := &fakeRuntime{
			connectedMachines: map[string]bool{"mac_1": true},
			runningAgents:     map[agentCall]bool{{MachineID: "mac_1", AgentID: "agt_1"}: true},
			sessionIDs:        map[agentCall]string{{MachineID: "mac_1", AgentID: "agt_1"}: "sess_1"},
			runtimeStatuses: map[agentCall]agentRuntimeStatus{
				{MachineID: "mac_1", AgentID: "agt_1"}: {Activity: "thinking", Detail: "Investigating"},
			},
		}
		router := newWebAgentRouter(Dependencies{AgentStore: fake, ReviewStore: fake, Runtime: runtime})

		resp := httputil.DoJSON(t, router, http.MethodPost, "/api/v1/workspaces/wsp_1/agents/runtime-snapshots", map[string]any{
			"agentIds": []string{" agt_1 ", "agt_1", "agt_2"},
		})
		require.Equal(t, http.StatusOK, resp.Code)
		require.Equal(t, []string{"agt_1", "agt_2"}, fake.lastRuntimeSnapshotIDs)

		var out dto.AgentRuntimeSnapshotsResponse
		require.NoError(t, json.Unmarshal(resp.Body.Bytes(), &out))
		require.Len(t, out.Snapshots, 1)
		require.Equal(t, "agt_1", out.Snapshots[0].AgentID)
		require.Equal(t, "online", out.Snapshots[0].MachineStatus)
		require.Equal(t, "active", out.Snapshots[0].Status)
		require.Equal(t, "thinking", out.Snapshots[0].Activity)
		require.Equal(t, "Investigating", out.Snapshots[0].ActivityDetail)
		require.NotNil(t, out.Snapshots[0].CurrentInstance)
		require.Equal(t, "sess_1", out.Snapshots[0].CurrentInstance.SessionID)
		require.Equal(t, "thinking", out.Snapshots[0].CurrentInstance.Activity)
	})

	t.Run("redacts live activity details and sessions for non-owners", func(t *testing.T) {
		fake := newFakeStore()
		fake.runtimeSnapshots = []agent.AgentRuntimeSnapshot{{
			AgentID:       "agt_shared",
			MachineID:     "mac_shared",
			MachineStatus: "offline",
			Status:        "inactive",
			Activity:      "offline",
		}}
		runtime := &fakeRuntime{
			connectedMachines: map[string]bool{"mac_shared": true},
			runningAgents:     map[agentCall]bool{{MachineID: "mac_shared", AgentID: "agt_shared"}: true},
			sessionIDs:        map[agentCall]string{{MachineID: "mac_shared", AgentID: "agt_shared"}: "sess_private"},
			runtimeStatuses: map[agentCall]agentRuntimeStatus{
				{MachineID: "mac_shared", AgentID: "agt_shared"}: {Activity: "working", Detail: "Running a private command"},
			},
		}
		router := newWebAgentRouter(Dependencies{AgentStore: fake, ReviewStore: fake, Runtime: runtime})

		resp := httputil.DoJSON(t, router, http.MethodPost, "/api/v1/workspaces/wsp_1/agents/runtime-snapshots", map[string]any{
			"agentIds": []string{"agt_shared"},
		})
		require.Equal(t, http.StatusOK, resp.Code)

		var out dto.AgentRuntimeSnapshotsResponse
		require.NoError(t, json.Unmarshal(resp.Body.Bytes(), &out))
		require.Len(t, out.Snapshots, 1)
		require.Equal(t, "active", out.Snapshots[0].Status)
		require.Equal(t, "online", out.Snapshots[0].Activity)
		require.Empty(t, out.Snapshots[0].ActivityDetail)
		require.Nil(t, out.Snapshots[0].CurrentInstance)
	})

	t.Run("empty request returns an empty response without store work", 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/runtime-snapshots", map[string]any{
			"agentIds": []string{" ", ""},
		})
		require.Equal(t, http.StatusOK, resp.Code)
		require.Nil(t, fake.lastRuntimeSnapshotIDs)

		var out dto.AgentRuntimeSnapshotsResponse
		require.NoError(t, json.Unmarshal(resp.Body.Bytes(), &out))
		require.Empty(t, out.Snapshots)
	})

	t.Run("rejects requests above the snapshot limit", func(t *testing.T) {
		fake := newFakeStore()
		router := newWebAgentRouter(Dependencies{AgentStore: fake, ReviewStore: fake})
		agentIDs := make([]string, 0, agent.MaxAgentRuntimeSnapshotIDs+1)
		for i := 0; i < agent.MaxAgentRuntimeSnapshotIDs+1; i++ {
			agentIDs = append(agentIDs, "agt_"+string(rune('a'+i)))
		}

		resp := httputil.DoJSON(t, router, http.MethodPost, "/api/v1/workspaces/wsp_1/agents/runtime-snapshots", map[string]any{
			"agentIds": agentIDs,
		})
		require.Equal(t, http.StatusBadRequest, resp.Code)
		require.Contains(t, resp.Body.String(), "too many agentIds")
		require.Nil(t, fake.lastRuntimeSnapshotIDs)
	})
}
