package domain

import (
	"encoding/json"
	"testing"

	"github.com/stretchr/testify/require"
)

func TestMessagePresentationValidateAllowlistAndTypedArguments(t *testing.T) {
	valid := NewWorkflowRecoveryPresentation("wri_1", "wfx_1", "wfx_1", 2, WorkflowRecoveryMaxAttempts)
	require.NoError(t, valid.Validate())

	cases := []struct {
		name string
		raw  string
	}{
		{"unknown version", `{"version":2,"key":"workflow.recovery.nudge","args":{"runId":"wri_1","stepId":"wfx_1","effectId":"wfx_1","attempt":1,"totalAttempts":5}}`},
		{"unknown key", `{"version":1,"key":"workflow.recovery.other","args":{"runId":"wri_1","stepId":"wfx_1","effectId":"wfx_1","attempt":1,"totalAttempts":5}}`},
		{"unknown arg", `{"version":1,"key":"workflow.recovery.nudge","args":{"runId":"wri_1","stepId":"wfx_1","effectId":"wfx_1","attempt":1,"totalAttempts":5,"locale":"zh-CN"}}`},
		{"wrong type", `{"version":1,"key":"workflow.recovery.nudge","args":{"runId":"wri_1","stepId":"wfx_1","effectId":"wfx_1","attempt":"1","totalAttempts":5}}`},
		{"attempt out of range", `{"version":1,"key":"workflow.recovery.nudge","args":{"runId":"wri_1","stepId":"wfx_1","effectId":"wfx_1","attempt":6,"totalAttempts":5}}`},
		{"missing arg", `{"version":1,"key":"workflow.recovery.nudge","args":{"runId":"wri_1","stepId":"wfx_1","effectId":"wfx_1","attempt":1}}`},
	}
	for _, testCase := range cases {
		t.Run(testCase.name, func(t *testing.T) {
			var presentation MessagePresentation
			require.NoError(t, json.Unmarshal([]byte(testCase.raw), &presentation))
			require.Error(t, presentation.Validate())
		})
	}
}

func TestWorkflowRecoveryPresentationCarriesStrictResponderMention(t *testing.T) {
	presentation := NewWorkflowRecoveryPresentationWithResponderMention(
		"wri_1", "wfx_1", "wfx_1", 1, WorkflowRecoveryMaxAttempts,
		WorkflowRecoveryResponderMention{Type: "agent", ID: "agt_frozen", Token: "helper"},
	)
	require.NoError(t, presentation.Validate())
	var args WorkflowRecoveryPresentationArgs
	require.NoError(t, json.Unmarshal(presentation.Args, &args))
	require.Equal(t, &WorkflowRecoveryResponderMention{Type: "agent", ID: "agt_frozen", Token: "helper"}, args.ResponderMention)

	updated, err := NewWorkflowRecoveryPresentation("wri_1", "wfx_1", "wfx_1", 1, WorkflowRecoveryMaxAttempts).
		WithWorkflowRecoveryResponderMention("agt_frozen", "@helper")
	require.NoError(t, err)
	require.Equal(t, presentation.Args, updated.Args)

	without, err := updated.WithoutWorkflowRecoveryResponderMention()
	require.NoError(t, err)
	require.Equal(t, NewWorkflowRecoveryPresentation("wri_1", "wfx_1", "wfx_1", 1, WorkflowRecoveryMaxAttempts).Args, without.Args)

	for _, raw := range []string{
		`{"version":1,"key":"workflow.recovery.nudge","args":{"runId":"wri_1","stepId":"wfx_1","effectId":"wfx_1","attempt":1,"totalAttempts":5,"responderMention":{"type":"human","id":"agt_frozen","token":"helper"}}}`,
		`{"version":1,"key":"workflow.recovery.nudge","args":{"runId":"wri_1","stepId":"wfx_1","effectId":"wfx_1","attempt":1,"totalAttempts":5,"responderMention":{"type":"agent","id":"agt_frozen","token":"@helper"}}}`,
		`{"version":1,"key":"workflow.recovery.nudge","args":{"runId":"wri_1","stepId":"wfx_1","effectId":"wfx_1","attempt":1,"totalAttempts":5,"responderMention":{"type":"agent","id":"agt_frozen","token":"helper","unexpected":true}}}`,
		`{"version":1,"key":"workflow.recovery.nudge","args":{"runId":"wri_1","stepId":"wfx_1","effectId":"wfx_1","attempt":1,"totalAttempts":5,"responderMention":null}}`,
	} {
		_, err := DecodeMessagePresentation([]byte(raw))
		require.Error(t, err)
	}
}

func TestMessagePresentationFromMetadataRejectsForgedOrMalformedEnvelope(t *testing.T) {
	valid := NewWorkflowRecoveryPresentation("wri_1", "wfx_1", "wfx_1", 1, WorkflowRecoveryMaxAttempts)
	value, err := valid.MetadataValue()
	require.NoError(t, err)
	decoded, err := MessagePresentationFromMetadata(map[string]any{
		MessagePresentationMetadataKey: value,
	})
	require.NoError(t, err)
	require.NotNil(t, decoded)
	require.Equal(t, MessagePresentationKeyWorkflowRecovery, decoded.Key)

	_, err = MessagePresentationFromMetadata(map[string]any{
		MessagePresentationMetadataKey: map[string]any{
			"version": 1,
			"key":     "workflow.recovery.nudge",
			"args": map[string]any{
				"runId": "wri_1", "stepId": "wfx_1", "effectId": "wfx_1",
				"attempt": 1, "totalAttempts": 5, "key": "arbitrary.client.key",
			},
		},
	})
	require.Error(t, err)
}

func TestWorkflowRunApprovalPresentationKeepsAuthoredSummaryAsDynamicArg(t *testing.T) {
	presentation := NewWorkflowRunApprovalPresentation(
		"pending", "pln_1", "plv_1", "wri_1", "review", "Agent-authored summary",
	)
	require.NoError(t, presentation.Validate())
	value, err := presentation.MetadataValue()
	require.NoError(t, err)
	var args WorkflowRunApprovalPresentationArgs
	encodedArgs, err := json.Marshal(value["args"])
	require.NoError(t, err)
	require.NoError(t, json.Unmarshal(encodedArgs, &args))
	require.Equal(t, "Agent-authored summary", args.Summary)
}
