package session

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

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

	"github.com/tidbcloud/AgentTeam/desktop/internal/memorywatcher"
)

type memorySyncStoreStub struct {
	status  memorywatcher.Status
	present bool
	retries []string
}

func (s *memorySyncStoreStub) MemorySyncStatus(string) (memorywatcher.Status, bool) {
	return s.status, s.present
}

func (s *memorySyncStoreStub) RetryMemorySync(_ context.Context, agentID string) {
	s.retries = append(s.retries, agentID)
}

func TestMemorySyncStatusHandlerReturnsTransientStatus(t *testing.T) {
	gin.SetMode(gin.TestMode)
	retryAt := time.Date(2026, time.August, 14, 15, 0, 0, 0, time.UTC)
	store := &memorySyncStoreStub{present: true, status: memorywatcher.Status{
		State:   memorywatcher.StatusPendingSync,
		Reason:  memorywatcher.StatusReasonPushFailed,
		RetryAt: retryAt,
	}}
	router := gin.New()
	router.GET("/agents/:agentId/memory-sync", NewMemorySyncStatusHandler(store))

	response := httptest.NewRecorder()
	router.ServeHTTP(response, httptest.NewRequest(http.MethodGet, "/agents/agt_1/memory-sync", nil))
	require.Equal(t, http.StatusOK, response.Code)
	var body struct {
		State   string    `json:"state"`
		Reason  string    `json:"reason"`
		RetryAt time.Time `json:"retryAt"`
	}
	require.NoError(t, json.Unmarshal(response.Body.Bytes(), &body))
	require.Equal(t, string(store.status.State), body.State)
	require.Equal(t, string(store.status.Reason), body.Reason)
	require.Equal(t, retryAt, body.RetryAt)
}

func TestMemorySyncStatusHandlerReturnsNotFoundWithoutRuntimeState(t *testing.T) {
	gin.SetMode(gin.TestMode)
	router := gin.New()
	router.GET("/agents/:agentId/memory-sync", NewMemorySyncStatusHandler(&memorySyncStoreStub{}))

	response := httptest.NewRecorder()
	router.ServeHTTP(response, httptest.NewRequest(http.MethodGet, "/agents/agt_1/memory-sync", nil))
	require.Equal(t, http.StatusNotFound, response.Code)
}

func TestMemorySyncRetryHandlerRoutesExplicitAgentRetry(t *testing.T) {
	gin.SetMode(gin.TestMode)
	store := &memorySyncStoreStub{present: true}
	router := gin.New()
	router.POST("/agents/:agentId/memory-sync/retry", NewMemorySyncRetryHandler(store))

	response := httptest.NewRecorder()
	router.ServeHTTP(response, httptest.NewRequest(http.MethodPost, "/agents/agt_1/memory-sync/retry", nil))
	require.Equal(t, http.StatusAccepted, response.Code)
	require.Equal(t, []string{"agt_1"}, store.retries)
}

func TestMemorySyncRetryHandlerRejectsUnknownRuntimeState(t *testing.T) {
	gin.SetMode(gin.TestMode)
	store := &memorySyncStoreStub{}
	router := gin.New()
	router.POST("/agents/:agentId/memory-sync/retry", NewMemorySyncRetryHandler(store))

	response := httptest.NewRecorder()
	router.ServeHTTP(response, httptest.NewRequest(http.MethodPost, "/agents/agt_unknown/memory-sync/retry", nil))
	require.Equal(t, http.StatusNotFound, response.Code)
	require.Empty(t, store.retries)
}
