package dashboard

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

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

	"github.com/tidbcloud/AgentTeam/desktop/internal/agent"
	"github.com/tidbcloud/AgentTeam/desktop/internal/api/dto"
	"github.com/tidbcloud/AgentTeam/desktop/internal/profile"
)

func setupDashboardTestProfile(t *testing.T) string {
	t.Helper()
	dir := t.TempDir()
	t.Setenv(profile.ConfigDirEnvKey, dir)
	_ = profile.Default()
	return dir
}

func TestAgentsBundleHandler(t *testing.T) {
	setupDashboardTestProfile(t)
	mgr := profile.Default()

	require.NoError(t, mgr.Agents().Add(agent.Config{
		ID:      "ag-1",
		Name:    "Alpha",
		Runtime: "claude",
	}))

	gin.SetMode(gin.TestMode)
	router := gin.New()
	router.GET("/bundles/agents", NewAgentsBundleHandler())

	req := httptest.NewRequest(http.MethodGet, "/bundles/agents", nil)
	rec := httptest.NewRecorder()
	router.ServeHTTP(rec, req)

	require.Equal(t, http.StatusOK, rec.Code, rec.Body.String())

	var resp dto.AgentsBundleResponse
	require.NoError(t, json.Unmarshal(rec.Body.Bytes(), &resp))
	require.Len(t, resp.Agents, 1)
	require.Equal(t, "ag-1", resp.Agents[0].ID)
}

func TestServersBundleHandler(t *testing.T) {
	setupDashboardTestProfile(t)
	mgr := profile.Default()

	require.NoError(t, mgr.Servers().Add(&profile.AgentTeamServer{
		ID: "ch-1",
	}))
	require.NoError(t, mgr.Agents().Add(agent.Config{
		ID:      "ag-1",
		Runtime: "claude",
	}))

	gin.SetMode(gin.TestMode)
	router := gin.New()
	router.GET("/bundles/servers", NewServersBundleHandler())

	req := httptest.NewRequest(http.MethodGet, "/bundles/servers", nil)
	rec := httptest.NewRecorder()
	router.ServeHTTP(rec, req)

	require.Equal(t, http.StatusOK, rec.Code, rec.Body.String())

	var resp dto.ServersBundleResponse
	require.NoError(t, json.Unmarshal(rec.Body.Bytes(), &resp))
	require.Len(t, resp.Servers, 1)
	require.Equal(t, "ch-1", resp.Servers[0].ID)
	require.Len(t, resp.Agents, 1)
	require.NotNil(t, resp.WindowSummary12h)
	require.NotNil(t, resp.WindowSummary1d)
}

func TestRuntimesBundleHandler(t *testing.T) {
	setupDashboardTestProfile(t)

	gin.SetMode(gin.TestMode)
	router := gin.New()
	router.GET("/bundles/runtimes", NewRuntimesBundleHandler())

	req := httptest.NewRequest(http.MethodGet, "/bundles/runtimes", nil)
	rec := httptest.NewRecorder()
	router.ServeHTTP(rec, req)

	require.Equal(t, http.StatusOK, rec.Code, rec.Body.String())

	var resp dto.RuntimesBundleResponse
	require.NoError(t, json.Unmarshal(rec.Body.Bytes(), &resp))
	require.NotNil(t, resp.Runtimes)
	require.NotNil(t, resp.Detected)
}

func TestSettingsBundleHandler(t *testing.T) {
	setupDashboardTestProfile(t)

	gin.SetMode(gin.TestMode)
	router := gin.New()
	router.GET("/bundles/settings", NewSettingsBundleHandler())

	req := httptest.NewRequest(http.MethodGet, "/bundles/settings", nil)
	rec := httptest.NewRecorder()
	router.ServeHTTP(rec, req)

	require.Equal(t, http.StatusOK, rec.Code, rec.Body.String())

	var resp dto.SettingsBundleResponse
	require.NoError(t, json.Unmarshal(rec.Body.Bytes(), &resp))
	require.NotNil(t, resp.SystemInfo)
}

func TestHomeBundleHandler(t *testing.T) {
	setupDashboardTestProfile(t)

	gin.SetMode(gin.TestMode)
	router := gin.New()
	router.GET("/bundles/home", NewHomeBundleHandler())

	t.Run("default window", func(t *testing.T) {
		req := httptest.NewRequest(http.MethodGet, "/bundles/home", nil)
		rec := httptest.NewRecorder()
		router.ServeHTTP(rec, req)
		require.Equal(t, http.StatusOK, rec.Code, rec.Body.String())

		var resp dto.HomeBundleResponse
		require.NoError(t, json.Unmarshal(rec.Body.Bytes(), &resp))
		require.NotNil(t, resp.SystemInfo)
	})

	t.Run("invalid window", func(t *testing.T) {
		req := httptest.NewRequest(http.MethodGet, "/bundles/home?window=bogus", nil)
		rec := httptest.NewRecorder()
		router.ServeHTTP(rec, req)
		require.Equal(t, http.StatusBadRequest, rec.Code, rec.Body.String())
	})
}

func TestAgentStatsBundleHandler(t *testing.T) {
	setupDashboardTestProfile(t)

	gin.SetMode(gin.TestMode)
	router := gin.New()
	router.GET("/bundles/agents/:agentId/stats", NewAgentStatsBundleHandler())

	t.Run("default window", func(t *testing.T) {
		req := httptest.NewRequest(http.MethodGet, "/bundles/agents/ag-1/stats", nil)
		rec := httptest.NewRecorder()
		router.ServeHTTP(rec, req)
		require.Equal(t, http.StatusOK, rec.Code, rec.Body.String())

		var resp dto.AgentStatsBundleResponse
		require.NoError(t, json.Unmarshal(rec.Body.Bytes(), &resp))
		require.NotNil(t, resp.MessageSummary)
		require.NotNil(t, resp.MessageTrend)
		require.NotNil(t, resp.MessageBar)
		require.NotNil(t, resp.TokenSummary)
		require.NotNil(t, resp.TokenTrend)
		require.NotNil(t, resp.InputTokenBar)
		require.NotNil(t, resp.CachedTokenBar)
		require.NotNil(t, resp.OutputTokenBar)
	})

	t.Run("invalid window", func(t *testing.T) {
		req := httptest.NewRequest(http.MethodGet, "/bundles/agents/ag-1/stats?window=bogus", nil)
		rec := httptest.NewRecorder()
		router.ServeHTTP(rec, req)
		require.Equal(t, http.StatusBadRequest, rec.Code, rec.Body.String())
	})
}
