package agent

import (
	"context"
	"errors"
	"testing"

	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/AgentTeam/desktop/internal/agent/drivercontract"
	"github.com/tidbcloud/AgentTeam/desktop/internal/agent/runtimeconfig"
	"github.com/tidbcloud/AgentTeam/desktop/internal/types"
)

type deliveryTestDriver struct{}

func (deliveryTestDriver) Name() string                    { return string(runtimeconfig.TypeCodex) }
func (deliveryTestDriver) SupportsStdinNotification() bool { return false }
func (deliveryTestDriver) MCPToolPrefix() string           { return "mcp__agentteam__" }
func (deliveryTestDriver) Spawn(context.Context, drivercontract.LaunchConfig) (drivercontract.SpawnResult, error) {
	return drivercontract.SpawnResult{}, errors.New("not implemented")
}
func (deliveryTestDriver) ParseLine(string) []drivercontract.ParsedEvent { return nil }
func (deliveryTestDriver) EncodeStdinMessage(string, string) []byte      { return nil }

type sessionlessInterruptTestDriver struct {
	deliveryTestDriver
	supportsSessionless bool
	calls               int
	lastSessionID       string
}

func (d *sessionlessInterruptTestDriver) Name() string { return string(runtimeconfig.TypeClaudeCode) }

func (d *sessionlessInterruptTestDriver) InterruptActiveRun(_ context.Context, sessionID string) error {
	d.calls++
	d.lastSessionID = sessionID
	return nil
}

func (d *sessionlessInterruptTestDriver) SupportsSessionlessActiveRunInterrupt() bool {
	return d.supportsSessionless
}

func TestProcessInterruptActiveRunAllowsSessionlessDriver(t *testing.T) {
	driver := &sessionlessInterruptTestDriver{supportsSessionless: true}
	ap := &Process{
		AgentID:               "agent-1",
		processRuntimeBinding: processRuntimeBinding{driver: driver},
		processLifecycleState: processLifecycleState{isIdle: false}}

	handled, err := ap.InterruptActiveRun(context.Background())

	require.NoError(t, err)
	require.True(t, handled)
	require.Equal(t, 1, driver.calls)
	require.Empty(t, driver.lastSessionID)
	require.True(t, ap.IsIdle())
}

func TestProcessInterruptActiveRunRejectsSessionlessDriverWithoutOptIn(t *testing.T) {
	driver := &sessionlessInterruptTestDriver{}
	ap := &Process{
		AgentID:               "agent-1",
		processRuntimeBinding: processRuntimeBinding{driver: driver},
		processLifecycleState: processLifecycleState{isIdle: false}}

	handled, err := ap.InterruptActiveRun(context.Background())

	require.NoError(t, err)
	require.False(t, handled)
	require.Zero(t, driver.calls)
	require.False(t, ap.IsIdle())
}

func TestProcessRenderDeliveryTextUsesWorkflowPresentationAuthor(t *testing.T) {
	ap := &Process{
		AgentID:               "agt-calculator",
		SessionID:             "thread-1",
		processRuntimeBinding: processRuntimeBinding{driver: deliveryTestDriver{}},
		processRecoveryState:  processRecoveryState{workDir: t.TempDir()},
	}

	text, err := ap.renderDeliveryTextWithContext(context.Background(), types.InboxMessage{
		MessageID: "msg-workflow-callback",
		Target:    "#agentteam",
		AuthorProfile: types.AuthorProfile{
			ActorType:   "human",
			PrincipalID: "usr_owner",
			DisplayName: "Arithmetic E2E Owner",
		},
		Source: types.ContributionSource{
			Kind:    "workflow_run",
			RefType: "workflow_run",
			RefID:   "wfr_calculator",
			RunID:   "wfr_calculator",
			EventID: "wrf_calculator_effect",
			Label:   "Parallel calculator",
		},
		Content: "Compute the next work item.",
	}, "turn_direct", "wake-workflow")
	require.NoError(t, err)
	require.Contains(t, text, "@Parallel calculator: Compute the next work item.")
	require.NotContains(t, text, "Arithmetic E2E Owner")
}

func TestProcessRenderDeliveryText_IncludesTeamContext(t *testing.T) {
	ap := &Process{
		AgentID:               "agt-leader",
		SessionID:             "thread-1",
		processRuntimeBinding: processRuntimeBinding{driver: deliveryTestDriver{}},
		processRecoveryState:  processRecoveryState{workDir: t.TempDir()}}

	text, err := ap.renderDeliveryTextWithContext(context.Background(), types.InboxMessage{
		MessageID:   "msg-team",
		TargetKey:   "th_product",
		TargetSeq:   42,
		Target:      "#product:abcd1234",
		ChannelType: "thread",
		AuthorProfile: types.AuthorProfile{
			ActorType:   "human",
			DisplayName: "alice",
		},
		Content:   "@product-engineering1 implement a todo list",
		Timestamp: "2026-06-23T14:00:00Z",
		TeamContexts: []types.TeamContext{{
			TeamID:            "team_product",
			TeamHandle:        "product-engineering1",
			TeamDisplayName:   "Product Engineering",
			TeamDescription:   "Coordinate the team before implementation.",
			TeamMemberID:      "member_leader",
			Role:              "leader",
			RoleLabel:         "leader",
			RoleOverlayPrompt: "Coordinate members. Do not implement features yourself.",
			MemberRoster: []types.TeamRosterMember{{
				ActorKind:         "agent",
				ActorID:           "agt-leader",
				DisplayName:       "Leader Agent",
				Handle:            "agentteam4-codex-gmh",
				Role:              "leader",
				RoleLabel:         "leader",
				RoleOverlayPrompt: "Coordinate members. Do not implement features yourself.",
				WakeOnTeamMention: true,
				DeliveryKind:      "wake",
				Self:              true,
			}, {
				ActorKind:         "agent",
				ActorID:           "agt-builder",
				DisplayName:       "Builder Agent",
				Handle:            "builder-agent",
				RoleLabel:         "builder",
				RoleOverlayPrompt: "Implement assigned feature slices.",
				WakeOnTeamMention: false,
				DeliveryKind:      "agent",
			}},
		}},
	}, "turn_direct", "wake-team")
	require.NoError(t, err)

	require.Contains(t, text, "team contexts:")
	require.Contains(t, text, "- team: @product-engineering1")
	require.Contains(t, text, "team id: team_product")
	require.Contains(t, text, "team invocation: you were awakened as this Team member. Other Team members may not have been awakened automatically.")
	require.Contains(t, text, "Team responsibility updates:")
	require.Contains(t, text, "team duty:\n    Coordinate the team before implementation.")
	require.Contains(t, text, "your role label: leader")
	require.Contains(t, text, "your duty:\n    Coordinate members. Do not implement features yourself.")
	require.Contains(t, text, "team member roster:\n    - @agentteam4-codex-gmh (Leader Agent) (agent, leader, active participant, self)")
	require.Contains(t, text, "      duty:\n        Coordinate members. Do not implement features yourself.")
	require.Contains(t, text, "    - @builder-agent (Builder Agent) (agent, builder, as-needed participant)")
	require.Contains(t, text, "      duty:\n        Implement assigned feature slices.")
}
