package dispatcher

import (
	"context"
	"os"
	"path/filepath"
	"strings"
	"testing"
	"time"

	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/AgentTeam/desktop/internal/agent"
	"github.com/tidbcloud/AgentTeam/desktop/internal/agent/drivercontract"
	"github.com/tidbcloud/AgentTeam/desktop/internal/agent/runtimeevents"
	"github.com/tidbcloud/AgentTeam/desktop/internal/profile"
)

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

	workDir := t.TempDir()
	memoryPath := filepath.Join(workDir, "MEMORY.md")
	require.NoError(t, os.WriteFile(memoryPath, []byte("# Old Agent\n\n## Active Context\n- idle\n"), 0o644))

	longTitle := strings.Repeat("超", 1000)
	require.NoError(t, rewriteAgentMemoryTitle(workDir, longTitle))

	memoryBytes, err := os.ReadFile(memoryPath)
	require.NoError(t, err)
	memoryText := string(memoryBytes)
	firstLine, _, _ := strings.Cut(memoryText, "\n")
	require.LessOrEqual(t, len([]rune(strings.TrimPrefix(firstLine, "# "))), 120)
	require.Contains(t, firstLine, "…")
	require.NotContains(t, memoryText, longTitle)
	require.Contains(t, memoryText, "## Active Context")
}

func TestUpdateAgentIdentityRefreshesRunningSessionSnapshot(t *testing.T) {
	t.Setenv("HOME", t.TempDir())
	t.Setenv(profile.ConfigDirEnvKey, filepath.Join(t.TempDir(), ".agentteam"))

	d := mustNewDispatcher("http://127.0.0.1:0")
	defer d.Close()
	agentID := "agent-identity-refresh"
	require.NoError(t, os.MkdirAll(sessionWorkDir(agentID), 0o755))
	process, err := agent.NewProcess(
		context.Background(),
		runningStubDriver{},
		drivercontract.LaunchConfig{AgentID: agentID, WorkDir: sessionWorkDir(agentID)},
		agent.ProcessOptions{},
	)
	require.NoError(t, err)
	d.sessionManager.Set(agentID, &interactiveSession{
		sessionKey:    agentID,
		agentID:       agentID,
		serverAgentID: agentID,
		agent: agent.Config{
			ID:      agentID,
			Name:    "Old Agent",
			Runtime: "codex",
		},
		process: process,
	})

	sub := d.SubscribeSessionStateChanges("test-update-identity-refresh")
	require.NotNil(t, sub)
	defer sub.Unsubscribe()

	d.UpdateAgentIdentity(agentID, "new-agent", "New Agent")

	snapshots := d.Sessions()
	require.Empty(t, snapshots, "a renamed live runtime must be retired so its immutable provider label cannot stay stale")
	select {
	case got := <-sub.Events():
		require.Equal(t, runtimeevents.KindSessionStateChanged, got.Kind)
		require.Equal(t, agentID, got.Context.AgentID)
	case <-time.After(time.Second):
		t.Fatal("timed out waiting for session state event")
	}
}

func TestUpdateAgentIdentityIsIdempotentForCatalogReconciliation(t *testing.T) {
	t.Setenv("HOME", t.TempDir())
	t.Setenv(profile.ConfigDirEnvKey, filepath.Join(t.TempDir(), ".agentteam"))

	d := mustNewDispatcher("http://127.0.0.1:0")
	defer d.Close()
	agentID := "agent-identity-idempotent"
	workDir := sessionWorkDir(agentID)
	require.NoError(t, os.MkdirAll(workDir, 0o755))
	_, _, _, err := persistAgentIdentityStartConfig(workDir, agentID, "same-agent", "Same Agent")
	require.NoError(t, err)
	require.NoError(t, os.WriteFile(filepath.Join(workDir, "MEMORY.md"), []byte("# Same Agent\n"), 0o644))

	d.UpdateAgentIdentity(agentID, "same-agent", "Same Agent")

	archiveBytes, err := os.ReadFile(filepath.Join(workDir, "archive", "checkpoints.md"))
	require.ErrorIs(t, err, os.ErrNotExist)
	require.Empty(t, archiveBytes)
}
