package run

import (
	"testing"

	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/AgentTeam/internal/core/domain"
	"github.com/tidbcloud/AgentTeam/internal/workflow/plan"
)

const reducerFeedbackScopePlan = `apiVersion: loop.plan/v1
kind: PlanVersion
input:
  feedback_scope: {type: scope, required: true}
graph:
  entry:
    nodeId: approve
    port: in
    input:
      feedback_scope: {ref: plan.input.feedback_scope}
  nodes:
  - id: approve
    type: request_approval
    input:
      feedback_scope: {type: scope, required: true}
    requestApproval:
      assignee: alice
      summary: Approve this run
      feedbackScope: {ref: input.feedback_scope}
      retry: {maxAttempts: 2, backoff: PT1S}
  - id: success
    type: end
    end: {outcome: succeeded}
  - id: failure
    type: end
    end: {outcome: failed, code: approval_failed}
  edges:
  - id: approved
    source: {nodeId: approve, port: approved}
    target: {nodeId: success, port: in}
  - id: rejected
    source: {nodeId: approve, port: rejected}
    target: {nodeId: failure, port: in}
  - id: failed
    source: {nodeId: approve, port: failed}
    target: {nodeId: failure, port: in}
`

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

	artifact, diagnostics, err := plan.Compile([]byte(reducerFeedbackScopePlan))
	require.NoError(t, err)
	require.Empty(t, diagnostics)
	graph, err := IndexArtifact(artifact)
	require.NoError(t, err)
	kernel, err := NewKernel(graph)
	require.NoError(t, err)

	initial := domain.MessageScopeValue{Kind: domain.MessageScopeKindTask, ScopeID: "tsk_abcdefghijklmn"}
	mutated := domain.MessageScopeValue{Kind: domain.MessageScopeKindChannel, ScopeID: "chn_abcdefghijklmn"}
	state, err := kernel.Start(Values{
		"feedback_scope": map[string]any{"kind": string(initial.Kind), "scopeId": initial.ScopeID},
	})
	require.NoError(t, err)
	transition, err := kernel.Step(state, reducerNow)
	require.NoError(t, err)
	require.Len(t, transition.Intents, 1)
	require.Equal(t, IntentApproval, transition.Intents[0].Kind)
	require.Equal(t, &initial, transition.Intents[0].FeedbackScope)

	// Mutating the live Plan graph and waiting activation input after the
	// reducer emitted the intent must not change its frozen request snapshot.
	node, ok := graph.Node("approve")
	require.True(t, ok)
	literal := plan.ArtifactExpression{Op: plan.ArtifactOpConst, ResultType: plan.TypeScope, Value: plan.ArtifactLiteral(`{"kind":"channel","scopeId":"chn_abcdefghijklmn"}`)}
	node.Config.RequestApproval.FeedbackScope = &literal
	transition.State.Input["feedback_scope"] = map[string]any{"kind": string(mutated.Kind), "scopeId": mutated.ScopeID}
	require.Equal(t, &initial, transition.Intents[0].FeedbackScope)
}

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

	kernel, _ := goldenKernel(t, "request_approval.json")
	state, err := kernel.Start(Values{})
	require.NoError(t, err)
	transition, err := kernel.Step(state, reducerNow)
	require.NoError(t, err)
	require.Len(t, transition.Intents, 1)
	require.Nil(t, transition.Intents[0].FeedbackScope)
}
