package taskboard

import (
	"context"
	"testing"
	"time"

	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/AgentTeam/internal/coredb"
)

func TestListTaskOptionsSortsAgentsByComputedLabel(t *testing.T) {
	ctx := context.Background()
	fixture := seedTaskboardUserFixture(t, ctx)

	seedTaskboardCustomChannelAgent(t, ctx, fixture.pool, fixture.workspaceID, fixture.channelID, fixture.machineID, seededTaskboardAgent{
		memberID:          "mem_task_detail_agent_z_member",
		agentID:           "agt_task_detail_agent_alpha",
		memberDisplayName: "",
		agentName:         "Alpha Sort Agent",
	})
	seedTaskboardCustomChannelAgent(t, ctx, fixture.pool, fixture.workspaceID, fixture.channelID, fixture.machineID, seededTaskboardAgent{
		memberID:          "mem_task_detail_agent_a_member",
		agentID:           "agt_task_detail_agent_zulu",
		memberDisplayName: "",
		agentName:         "Zulu Sort Agent",
	})

	response, err := fixture.service.ListTaskOptions(ctx, ListTaskOptionsRequest{
		Context: NewAgentServiceContext(fixture.workspaceID, fixture.agentID, fixture.agentMemberID),
		Board:   BoardRef{Channel: "#all"},
		Role:    "agent",
	})
	require.NoError(t, err)
	require.Len(t, response.AssigneeOptions, 3)

	labels := []string{
		response.AssigneeOptions[0].Label,
		response.AssigneeOptions[1].Label,
		response.AssigneeOptions[2].Label,
	}
	require.Equal(t, []string{
		"Alpha Sort Agent",
		fixture.agentDisplayName,
		"Zulu Sort Agent",
	}, labels)
}

func TestTaskActivityLeavesUnknownUserDisplayEmptyForFrontendFallback(t *testing.T) {
	ctx := context.Background()
	fixture := seedTaskboardUserFixture(t, ctx)

	createdResponse, err := fixture.service.CreateTasks(ctx, CreateTasksRequest{
		Context: NewUserServiceContext(fixture.workspaceID, fixture.ownerUserID, fixture.ownerDisplayName),
		Board:   BoardRef{ChannelID: fixture.channelID},
		Titles:  []string{"Activity fallback should still resolve actor refs"},
	})
	require.NoError(t, err)
	require.Len(t, createdResponse.Tasks, 1)

	taskID := createdResponse.Tasks[0].ID

	mustExecTaskboard(t, ctx, fixture.pool, `
UPDATE members
SET display_name = ''
WHERE id = $1
`, fixture.ownerMemberID)
	mustExecTaskboard(t, ctx, fixture.pool, `
UPDATE users
SET name = '',
    display_name = ''
WHERE id = $1
`, fixture.ownerUserID)

	_, err = fixture.service.AddTaskCheckpoint(ctx, AddTaskCheckpointRequest{
		Context: NewUserServiceContext(fixture.workspaceID, fixture.ownerUserID, fixture.ownerDisplayName),
		Task:    TaskRef{TaskID: taskID},
		Checkpoint: TaskCheckpointInput{
			Text: "Owner checkpoint should still resolve through actorRef fallback.",
		},
	})
	require.NoError(t, err)

	timelineResponse, err := fixture.service.GetTaskTimeline(ctx, GetTaskTimelineRequest{
		Context: NewUserServiceContext(fixture.workspaceID, fixture.ownerUserID, fixture.ownerDisplayName),
		Task:    TaskRef{TaskID: taskID},
	})
	require.NoError(t, err)
	activityEvents := taskTimelineActivityEvents(timelineResponse)
	require.NotEmpty(t, activityEvents)
	require.Equal(t, taskEventCheckpointAdded, activityEvents[0].Type)
	require.Equal(t, fixture.ownerMemberID, activityEvents[0].ActorRef)
	require.Empty(t, activityEvents[0].ActorDisplayName)
}

type seededTaskboardAgent struct {
	memberID          string
	agentID           string
	memberDisplayName string
	agentName         string
}

func seedTaskboardCustomChannelAgent(t *testing.T, ctx context.Context, db interface {
	Exec(context.Context, string, ...any) (coredb.Result, error)
}, workspaceID string, channelID string, machineID string, agent seededTaskboardAgent) {
	t.Helper()

	now := time.Date(2026, 4, 13, 9, 45, 0, 0, time.UTC)

	mustExecTaskboard(t, ctx, db, `
INSERT INTO members (id, workspace_id, type, display_name, status, created_at, updated_at)
VALUES ($1, $2, 'agent', $3, 'active', $4, $4)
`, agent.memberID, workspaceID, agent.memberDisplayName, now)

	mustExecTaskboard(t, ctx, db, `
INSERT INTO scope_memberships (
    scope_id, member_id, visibility, owner_member_id, last_read_seq,
    last_read_global_seq, last_activity_global_seq,
    owner_context_dismissed_through_global_seq, effective_from_seq,
    effective_to_seq, created_at, updated_at, removed_at, archived_at
)
VALUES ($1, $2, 'public', NULL, 0, 0, 0, 0, 0, NULL, $3, $3, NULL, NULL)
`, channelID, agent.memberID, now)

	mustExecTaskboard(t, ctx, db, `
INSERT INTO agents (id, workspace_id, machine_id, member_id, name, avatar_url, runtime, model, reasoning_effort, description, session_id, auto_wake_enabled, status, activity, activity_detail, created_at, updated_at)
VALUES ($1, $2, $3, $4, $5, '', 'codex', 'gpt-5.4', '', '', '', TRUE, 'active', 'online', '', $6, $6)
`, agent.agentID, workspaceID, machineID, agent.memberID, agent.agentName, now)

}
