package models

import (
	"encoding/json"
	"fmt"
	"math/rand"
	"net/url"
	"sync"
	"testing"
	"time"

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

func TestNewCreateQueueRequest(t *testing.T) {
	CurrentEnvironment.QueueAttributeDefaults.MaximumMessageSize = 262144
	CurrentEnvironment.QueueAttributeDefaults.MessageRetentionPeriod = 345600
	CurrentEnvironment.QueueAttributeDefaults.ReceiveMessageWaitTimeSeconds = 10
	CurrentEnvironment.QueueAttributeDefaults.VisibilityTimeout = 30
	defer func() {
		ResetApp()
	}()

	expectedCreateQueueRequest := &CreateQueueRequest{
		Attributes: QueueAttributes{
			DelaySeconds:                  0,
			MaximumMessageSize:            262144,
			MessageRetentionPeriod:        345600,
			ReceiveMessageWaitTimeSeconds: 10,
			VisibilityTimeout:             30,
		},
	}

	result := NewCreateQueueRequest()

	assert.Equal(t, expectedCreateQueueRequest, result)
}

func TestCreateQueueRequest_SetAttributesFromForm_success(t *testing.T) {
	expectedRedrivePolicy := RedrivePolicy{
		MaxReceiveCount:     100,
		DeadLetterTargetArn: "dead-letter-queue-arn",
	}

	form := url.Values{}
	form.Add("Action", "CreateQueue")
	form.Add("QueueName", "new-queue")
	form.Add("Version", "2012-11-05")
	form.Add("Attribute.1.Name", "DelaySeconds")
	form.Add("Attribute.1.Value", "1")
	form.Add("Attribute.2.Name", "MaximumMessageSize")
	form.Add("Attribute.2.Value", "2")
	form.Add("Attribute.3.Name", "MessageRetentionPeriod")
	form.Add("Attribute.3.Value", "3")
	form.Add("Attribute.4.Name", "Policy")
	form.Add("Attribute.4.Value", "{\"i-am\":\"the-policy\"}")
	form.Add("Attribute.5.Name", "ReceiveMessageWaitTimeSeconds")
	form.Add("Attribute.5.Value", "4")
	form.Add("Attribute.6.Name", "VisibilityTimeout")
	form.Add("Attribute.6.Value", "5")
	form.Add("Attribute.7.Name", "RedrivePolicy")
	form.Add("Attribute.7.Value", "{\"maxReceiveCount\": 100, \"deadLetterTargetArn\":\"dead-letter-queue-arn\"}")
	form.Add("Attribute.8.Name", "RedriveAllowPolicy")
	form.Add("Attribute.8.Value", "{\"i-am\":\"the-redrive-allow-policy\"}")

	cqr := &CreateQueueRequest{
		Attributes: QueueAttributes{
			DelaySeconds:                  1,
			MaximumMessageSize:            262144,
			MessageRetentionPeriod:        345600,
			ReceiveMessageWaitTimeSeconds: 10,
			VisibilityTimeout:             30,
		},
	}
	cqr.SetAttributesFromForm(form)

	assert.Equal(t, StringToInt(1), cqr.Attributes.DelaySeconds)
	assert.Equal(t, StringToInt(2), cqr.Attributes.MaximumMessageSize)
	assert.Equal(t, StringToInt(3), cqr.Attributes.MessageRetentionPeriod)
	assert.Equal(t, map[string]interface{}{"i-am": "the-policy"}, cqr.Attributes.Policy)
	assert.Equal(t, StringToInt(4), cqr.Attributes.ReceiveMessageWaitTimeSeconds)
	assert.Equal(t, StringToInt(5), cqr.Attributes.VisibilityTimeout)
	assert.Equal(t, expectedRedrivePolicy, cqr.Attributes.RedrivePolicy)
	assert.Equal(t, map[string]interface{}{"i-am": "the-redrive-allow-policy"}, cqr.Attributes.RedriveAllowPolicy)
}

func TestCreateQueueRequest_SetAttributesFromForm_success_handles_redrive_recieve_count_int(t *testing.T) {
	expectedRedrivePolicy := RedrivePolicy{
		MaxReceiveCount:     100,
		DeadLetterTargetArn: "dead-letter-queue-arn",
	}

	form := url.Values{}
	form.Add("Attribute.1.Name", "RedrivePolicy")
	form.Add("Attribute.1.Value", "{\"maxReceiveCount\": 100, \"deadLetterTargetArn\":\"dead-letter-queue-arn\"}")

	cqr := &CreateQueueRequest{
		Attributes: QueueAttributes{},
	}
	cqr.SetAttributesFromForm(form)

	assert.Equal(t, expectedRedrivePolicy, cqr.Attributes.RedrivePolicy)
}

func TestCreateQueueRequest_SetAttributesFromForm_success_handles_redrive_recieve_count_string(t *testing.T) {
	expectedRedrivePolicy := RedrivePolicy{
		MaxReceiveCount:     100,
		DeadLetterTargetArn: "dead-letter-queue-arn",
	}

	form := url.Values{}
	form.Add("Attribute.1.Name", "RedrivePolicy")
	form.Add("Attribute.1.Value", "{\"maxReceiveCount\": \"100\", \"deadLetterTargetArn\":\"dead-letter-queue-arn\"}")

	cqr := &CreateQueueRequest{
		Attributes: QueueAttributes{},
	}
	cqr.SetAttributesFromForm(form)

	assert.Equal(t, expectedRedrivePolicy, cqr.Attributes.RedrivePolicy)
}

func TestCreateQueueRequest_SetAttributesFromForm_success_default_unparsable_redrive_recieve_count(t *testing.T) {
	defaultRedrivePolicy := RedrivePolicy{
		MaxReceiveCount:     10,
		DeadLetterTargetArn: "dead-letter-queue-arn",
	}

	form := url.Values{}
	form.Add("Attribute.1.Name", "RedrivePolicy")
	form.Add("Attribute.1.Value", "{\"maxReceiveCount\": null, \"deadLetterTargetArn\":\"dead-letter-queue-arn\"}")

	cqr := &CreateQueueRequest{
		Attributes: QueueAttributes{},
	}
	cqr.SetAttributesFromForm(form)

	assert.Equal(t, defaultRedrivePolicy, cqr.Attributes.RedrivePolicy)
}

func TestCreateQueueRequest_SetAttributesFromForm_success_skips_invalid_values(t *testing.T) {
	form := url.Values{}
	form.Add("Attribute.1.Name", "DelaySeconds")
	form.Add("Attribute.1.Value", "garbage")
	form.Add("Attribute.2.Name", "MaximumMessageSize")
	form.Add("Attribute.2.Value", "garbage")
	form.Add("Attribute.3.Name", "MessageRetentionPeriod")
	form.Add("Attribute.3.Value", "garbage")
	form.Add("Attribute.4.Name", "Policy")
	form.Add("Attribute.4.Value", "garbage")
	form.Add("Attribute.5.Name", "ReceiveMessageWaitTimeSeconds")
	form.Add("Attribute.5.Value", "garbage")
	form.Add("Attribute.6.Name", "VisibilityTimeout")
	form.Add("Attribute.6.Value", "garbage")
	form.Add("Attribute.7.Name", "RedrivePolicy")
	form.Add("Attribute.7.Value", "garbage")
	form.Add("Attribute.8.Name", "RedriveAllowPolicy")
	form.Add("Attribute.8.Value", "garbage")

	cqr := &CreateQueueRequest{
		Attributes: QueueAttributes{
			DelaySeconds:                  1,
			MaximumMessageSize:            262144,
			MessageRetentionPeriod:        345600,
			ReceiveMessageWaitTimeSeconds: 10,
			VisibilityTimeout:             30,
		},
	}
	cqr.SetAttributesFromForm(form)

	assert.Equal(t, StringToInt(1), cqr.Attributes.DelaySeconds)
	assert.Equal(t, StringToInt(262144), cqr.Attributes.MaximumMessageSize)
	assert.Equal(t, StringToInt(345600), cqr.Attributes.MessageRetentionPeriod)
	assert.Equal(t, map[string]interface{}(nil), cqr.Attributes.Policy)
	assert.Equal(t, StringToInt(10), cqr.Attributes.ReceiveMessageWaitTimeSeconds)
	assert.Equal(t, StringToInt(30), cqr.Attributes.VisibilityTimeout)
	assert.Equal(t, RedrivePolicy{}, cqr.Attributes.RedrivePolicy)
	assert.Equal(t, map[string]interface{}(nil), cqr.Attributes.RedriveAllowPolicy)
}

func TestRedrivePolicy_UnmarshalJSON_handles_nested_json(t *testing.T) {
	request := struct {
		MaxReceiveCount     int    `json:"maxReceiveCount"`
		DeadLetterTargetArn string `json:"deadLetterTargetArn"`
	}{
		MaxReceiveCount:     100,
		DeadLetterTargetArn: "arn:redrive-queue",
	}
	b, _ := json.Marshal(request)
	var r = RedrivePolicy{}
	err := r.UnmarshalJSON(b)

	assert.Nil(t, err)
	assert.Equal(t, StringToInt(100), r.MaxReceiveCount)
	assert.Equal(t, fmt.Sprintf("%s:%s", "arn", "redrive-queue"), r.DeadLetterTargetArn)
}

func TestRedrivePolicy_UnmarshalJSON_handles_escaped_string(t *testing.T) {
	request := `{"maxReceiveCount":"100","deadLetterTargetArn":"arn:redrive-queue"}`
	b, _ := json.Marshal(request)
	var r = RedrivePolicy{}
	err := r.UnmarshalJSON(b)

	assert.Nil(t, err)
	assert.Equal(t, StringToInt(100), r.MaxReceiveCount)
	assert.Equal(t, fmt.Sprintf("%s:%s", "arn", "redrive-queue"), r.DeadLetterTargetArn)
}

func TestRedrivePolicy_UnmarshalJSON_invalid_json_request_returns_error(t *testing.T) {
	request := fmt.Sprintf(`{\"maxReceiveCount\":\"100\",\"deadLetterTargetArn\":\"arn:redrive-queue\"}`)
	var r = RedrivePolicy{}
	err := r.UnmarshalJSON([]byte(request))

	assert.Error(t, err)
	assert.Equal(t, StringToInt(0), r.MaxReceiveCount)
	assert.Equal(t, "", r.DeadLetterTargetArn)
}

func TestRedrivePolicy_UnmarshalJSON_invalid_type_returns_error(t *testing.T) {
	request := `{"maxReceiveCount":true,"deadLetterTargetArn":"arn:redrive-queue"}`
	b, _ := json.Marshal(request)
	var r = RedrivePolicy{}
	err := r.UnmarshalJSON(b)

	assert.Error(t, err)
	assert.Equal(t, StringToInt(0), r.MaxReceiveCount)
	assert.Equal(t, "", r.DeadLetterTargetArn)
}

func TestNewListQueuesRequest_SetAttributesFromForm(t *testing.T) {
	form := url.Values{}
	form.Add("MaxResults", "1")
	form.Add("NextToken", "next-token")
	form.Add("QueueNamePrefix", "queue-name-prefix")

	lqr := &ListQueueRequest{}
	lqr.SetAttributesFromForm(form)

	assert.Equal(t, 1, lqr.MaxResults)
	assert.Equal(t, "next-token", lqr.NextToken)
	assert.Equal(t, "queue-name-prefix", lqr.QueueNamePrefix)
}

func TestListQueuesRequest_SetAttributesFromForm_invalid_max_results(t *testing.T) {
	form := url.Values{}
	form.Add("MaxResults", "1.0")
	form.Add("NextToken", "next-token")
	form.Add("QueueNamePrefix", "queue-name-prefix")

	lqr := &ListQueueRequest{}
	lqr.SetAttributesFromForm(form)

	assert.Equal(t, 0, lqr.MaxResults)
	assert.Equal(t, "next-token", lqr.NextToken)
	assert.Equal(t, "queue-name-prefix", lqr.QueueNamePrefix)
}

func TestGetQueueAttributesRequest_SetAttributesFromForm(t *testing.T) {
	form := url.Values{}
	form.Add("QueueUrl", "queue-url")
	form.Add("AttributeName.1", "attribute-1")
	form.Add("AttributeName.2", "attribute-2")

	lqr := &GetQueueAttributesRequest{}
	lqr.SetAttributesFromForm(form)

	assert.Equal(t, "queue-url", lqr.QueueUrl)
	assert.Equal(t, 2, len(lqr.AttributeNames))
	assert.Contains(t, lqr.AttributeNames, "attribute-1")
	assert.Contains(t, lqr.AttributeNames, "attribute-2")
}

func TestGetQueueAttributesRequest_SetAttributesFromForm_skips_invalid_key_sequence(t *testing.T) {
	form := url.Values{}
	form.Add("QueueUrl", "queue-url")
	form.Add("AttributeName.1", "attribute-1")
	form.Add("AttributeName.3", "attribute-3")

	lqr := &GetQueueAttributesRequest{}
	lqr.SetAttributesFromForm(form)

	assert.Equal(t, "queue-url", lqr.QueueUrl)
	assert.Equal(t, 1, len(lqr.AttributeNames))
	assert.Contains(t, lqr.AttributeNames, "attribute-1")
}

func TestSendMessageRequest_SetAttributesFromForm_success(t *testing.T) {
	form := url.Values{}
	form.Add("MessageAttribute.1.Name", "Attr1")
	form.Add("MessageAttribute.1.Value.DataType", "String")
	form.Add("MessageAttribute.1.Value.StringValue", "Value1")
	form.Add("MessageAttribute.2.Name", "Attr2")
	form.Add("MessageAttribute.2.Value.DataType", "Binary")
	form.Add("MessageAttribute.2.Value.BinaryValue", "VmFsdWUy")
	form.Add("MessageAttribute.3.Name", "")
	form.Add("MessageAttribute.3.Value.DataType", "String")
	form.Add("MessageAttribute.3.Value.StringValue", "Value")
	form.Add("MessageAttribute.4.Name", "Attr4")
	form.Add("MessageAttribute.4.Value.DataType", "")
	form.Add("MessageAttribute.4.Value.StringValue", "Value4")

	r := &SendMessageRequest{
		MessageAttributes:       make(map[string]MessageAttribute),
		MessageSystemAttributes: make(map[string]MessageAttribute),
	}
	r.SetAttributesFromForm(form)

	assert.Equal(t, 2, len(r.MessageAttributes))

	assert.NotNil(t, r.MessageAttributes["Attr1"])
	attr1 := r.MessageAttributes["Attr1"]
	assert.Equal(t, "String", attr1.DataType)
	assert.Equal(t, "Value1", attr1.StringValue)
	assert.Empty(t, attr1.BinaryValue)

	assert.NotNil(t, r.MessageAttributes["Attr2"])
	attr2 := r.MessageAttributes["Attr2"]
	assert.Equal(t, "Binary", attr2.DataType)
	assert.Empty(t, attr2.StringValue)
	assert.Equal(t, "VmFsdWUy", attr2.BinaryValue)
}

func TestSetQueueAttributesRequest_SetAttributesFromForm_success(t *testing.T) {
	expectedRedrivePolicy := RedrivePolicy{
		MaxReceiveCount:     100,
		DeadLetterTargetArn: "dead-letter-queue-arn",
	}

	form := url.Values{}
	form.Add("Action", "CreateQueue")
	form.Add("QueueName", "new-queue")
	form.Add("Version", "2012-11-05")
	form.Add("Attribute.1.Name", "DelaySeconds")
	form.Add("Attribute.1.Value", "1")
	form.Add("Attribute.2.Name", "MaximumMessageSize")
	form.Add("Attribute.2.Value", "2")
	form.Add("Attribute.3.Name", "MessageRetentionPeriod")
	form.Add("Attribute.3.Value", "3")
	form.Add("Attribute.4.Name", "Policy")
	form.Add("Attribute.4.Value", "{\"i-am\":\"the-policy\"}")
	form.Add("Attribute.5.Name", "ReceiveMessageWaitTimeSeconds")
	form.Add("Attribute.5.Value", "4")
	form.Add("Attribute.6.Name", "VisibilityTimeout")
	form.Add("Attribute.6.Value", "5")
	form.Add("Attribute.7.Name", "RedrivePolicy")
	form.Add("Attribute.7.Value", "{\"maxReceiveCount\": 100, \"deadLetterTargetArn\":\"dead-letter-queue-arn\"}")
	form.Add("Attribute.8.Name", "RedriveAllowPolicy")
	form.Add("Attribute.8.Value", "{\"i-am\":\"the-redrive-allow-policy\"}")

	cqr := &SetQueueAttributesRequest{
		Attributes: QueueAttributes{
			DelaySeconds:                  1,
			MaximumMessageSize:            262144,
			MessageRetentionPeriod:        345600,
			ReceiveMessageWaitTimeSeconds: 10,
			VisibilityTimeout:             30,
		},
	}
	cqr.SetAttributesFromForm(form)

	assert.Equal(t, StringToInt(1), cqr.Attributes.DelaySeconds)
	assert.Equal(t, StringToInt(2), cqr.Attributes.MaximumMessageSize)
	assert.Equal(t, StringToInt(3), cqr.Attributes.MessageRetentionPeriod)
	assert.Equal(t, map[string]interface{}{"i-am": "the-policy"}, cqr.Attributes.Policy)
	assert.Equal(t, StringToInt(4), cqr.Attributes.ReceiveMessageWaitTimeSeconds)
	assert.Equal(t, StringToInt(5), cqr.Attributes.VisibilityTimeout)
	assert.Equal(t, expectedRedrivePolicy, cqr.Attributes.RedrivePolicy)
	assert.Equal(t, map[string]interface{}{"i-am": "the-redrive-allow-policy"}, cqr.Attributes.RedriveAllowPolicy)
}

func TestSetQueueAttributesRequest_SetAttributesFromForm_success_handles_redrive_recieve_count_int(t *testing.T) {
	expectedRedrivePolicy := RedrivePolicy{
		MaxReceiveCount:     100,
		DeadLetterTargetArn: "dead-letter-queue-arn",
	}

	form := url.Values{}
	form.Add("Attribute.1.Name", "RedrivePolicy")
	form.Add("Attribute.1.Value", "{\"maxReceiveCount\": 100, \"deadLetterTargetArn\":\"dead-letter-queue-arn\"}")

	cqr := &SetQueueAttributesRequest{
		Attributes: QueueAttributes{},
	}
	cqr.SetAttributesFromForm(form)

	assert.Equal(t, expectedRedrivePolicy, cqr.Attributes.RedrivePolicy)
}

func TestSetQueueAttributesRequest_SetAttributesFromForm_success_handles_redrive_recieve_count_string(t *testing.T) {
	expectedRedrivePolicy := RedrivePolicy{
		MaxReceiveCount:     100,
		DeadLetterTargetArn: "dead-letter-queue-arn",
	}

	form := url.Values{}
	form.Add("Attribute.1.Name", "RedrivePolicy")
	form.Add("Attribute.1.Value", "{\"maxReceiveCount\": \"100\", \"deadLetterTargetArn\":\"dead-letter-queue-arn\"}")

	cqr := &SetQueueAttributesRequest{
		Attributes: QueueAttributes{},
	}
	cqr.SetAttributesFromForm(form)

	assert.Equal(t, expectedRedrivePolicy, cqr.Attributes.RedrivePolicy)
}

func TestSetQueueAttributesRequest_SetAttributesFromForm_success_default_unparsable_redrive_recieve_count(t *testing.T) {
	defaultRedrivePolicy := RedrivePolicy{
		MaxReceiveCount:     10,
		DeadLetterTargetArn: "dead-letter-queue-arn",
	}

	form := url.Values{}
	form.Add("Attribute.1.Name", "RedrivePolicy")
	form.Add("Attribute.1.Value", "{\"maxReceiveCount\": null, \"deadLetterTargetArn\":\"dead-letter-queue-arn\"}")

	cqr := &SetQueueAttributesRequest{
		Attributes: QueueAttributes{},
	}
	cqr.SetAttributesFromForm(form)

	assert.Equal(t, defaultRedrivePolicy, cqr.Attributes.RedrivePolicy)
}

func TestSetQueueAttributesRequest_SetAttributesFromForm_success_skips_invalid_values(t *testing.T) {
	form := url.Values{}
	form.Add("Attribute.1.Name", "DelaySeconds")
	form.Add("Attribute.1.Value", "garbage")
	form.Add("Attribute.2.Name", "MaximumMessageSize")
	form.Add("Attribute.2.Value", "garbage")
	form.Add("Attribute.3.Name", "MessageRetentionPeriod")
	form.Add("Attribute.3.Value", "garbage")
	form.Add("Attribute.4.Name", "Policy")
	form.Add("Attribute.4.Value", "garbage")
	form.Add("Attribute.5.Name", "ReceiveMessageWaitTimeSeconds")
	form.Add("Attribute.5.Value", "garbage")
	form.Add("Attribute.6.Name", "VisibilityTimeout")
	form.Add("Attribute.6.Value", "garbage")
	form.Add("Attribute.7.Name", "RedrivePolicy")
	form.Add("Attribute.7.Value", "garbage")
	form.Add("Attribute.8.Name", "RedriveAllowPolicy")
	form.Add("Attribute.8.Value", "garbage")

	cqr := &SetQueueAttributesRequest{
		Attributes: QueueAttributes{
			DelaySeconds:                  1,
			MaximumMessageSize:            262144,
			MessageRetentionPeriod:        345600,
			ReceiveMessageWaitTimeSeconds: 10,
			VisibilityTimeout:             30,
		},
	}
	cqr.SetAttributesFromForm(form)

	assert.Equal(t, StringToInt(1), cqr.Attributes.DelaySeconds)
	assert.Equal(t, StringToInt(262144), cqr.Attributes.MaximumMessageSize)
	assert.Equal(t, StringToInt(345600), cqr.Attributes.MessageRetentionPeriod)
	assert.Equal(t, map[string]interface{}(nil), cqr.Attributes.Policy)
	assert.Equal(t, StringToInt(10), cqr.Attributes.ReceiveMessageWaitTimeSeconds)
	assert.Equal(t, StringToInt(30), cqr.Attributes.VisibilityTimeout)
	assert.Equal(t, RedrivePolicy{}, cqr.Attributes.RedrivePolicy)
	assert.Equal(t, map[string]interface{}(nil), cqr.Attributes.RedriveAllowPolicy)
}

func TestNewCreateTopicRequest(t *testing.T) {
	defer func() {
		ResetApp()
	}()

	result := NewCreateTopicRequest()

	assert.Equal(t, false, result.Attributes.FifoTopic)
	assert.Equal(t, StringToInt(1), result.Attributes.SignatureVersion)
	assert.Equal(t, "Active", result.Attributes.TracingConfig)
	assert.Equal(t, false, result.Attributes.ContentBasedDeduplication)
}

func TestCreateTopicRequest_SetAttributesFromForm_success(t *testing.T) {
	form := url.Values{}
	form.Add("Action", "CreateQueue")
	form.Add("QueueName", "new-queue")
	form.Add("Version", "2012-11-05")
	form.Add("Attribute.1.Name", "DeliveryPolicy")
	form.Add("Attribute.1.Value", "{\"i-am\":\"the-policy\", \"name\":\"delivery-policy\"}")
	form.Add("Attribute.2.Name", "DisplayName")
	form.Add("Attribute.2.Value", "Foo")
	form.Add("Attribute.3.Name", "FifoTopic")
	form.Add("Attribute.3.Value", "true")
	form.Add("Attribute.4.Name", "Policy")
	form.Add("Attribute.4.Value", "{\"i-am\":\"the-policy\", \"name\":\"policy\"}")
	form.Add("Attribute.5.Name", "SignatureVersion")
	form.Add("Attribute.5.Value", "99")
	form.Add("Attribute.6.Name", "TracingConfig")
	form.Add("Attribute.6.Value", "PassThrough")
	form.Add("Attribute.7.Name", "KmsMasterKeyId")
	form.Add("Attribute.7.Value", "1234abcd-12ab-34cd-56ef-1234567890ab")
	form.Add("Attribute.8.Name", "ArchivePolicy")
	form.Add("Attribute.8.Value", "{\"i-am\":\"the-policy\", \"name\":\"archive-policy\"}")
	form.Add("Attribute.9.Name", "BeginningArchiveTime")
	form.Add("Attribute.9.Value", "2024-07-01T23:59:59+09:00")
	form.Add("Attribute.10.Name", "ContentBasedDeduplication")
	form.Add("Attribute.10.Value", "true")

	ctr := &CreateTopicRequest{}
	ctr.SetAttributesFromForm(form)

	assert.Equal(t, 2, len(ctr.Attributes.DeliveryPolicy))
	assert.Equal(t, "the-policy", ctr.Attributes.DeliveryPolicy["i-am"])
	assert.Equal(t, "delivery-policy", ctr.Attributes.DeliveryPolicy["name"])
	assert.Equal(t, "Foo", ctr.Attributes.DisplayName)
	assert.Equal(t, true, ctr.Attributes.FifoTopic)
	assert.Equal(t, 2, len(ctr.Attributes.Policy))
	assert.Equal(t, "the-policy", ctr.Attributes.Policy["i-am"])
	assert.Equal(t, "policy", ctr.Attributes.Policy["name"])
	assert.Equal(t, StringToInt(99), ctr.Attributes.SignatureVersion)
	assert.Equal(t, "PassThrough", ctr.Attributes.TracingConfig)
	assert.Equal(t, "1234abcd-12ab-34cd-56ef-1234567890ab", ctr.Attributes.KmsMasterKeyId)
	assert.Equal(t, 2, len(ctr.Attributes.ArchivePolicy))
	assert.Equal(t, "the-policy", ctr.Attributes.ArchivePolicy["i-am"])
	assert.Equal(t, "archive-policy", ctr.Attributes.ArchivePolicy["name"])
	assert.Equal(t, "2024-07-01T23:59:59+09:00", ctr.Attributes.BeginningArchiveTime)
	assert.Equal(t, true, ctr.Attributes.ContentBasedDeduplication)
}

func TestSubscribeRequest_SetAttributesFromForm_success(t *testing.T) {
	form := url.Values{}
	form.Add("Attributes.entry.1.key", "RawMessageDelivery")
	form.Add("Attributes.entry.1.value", "true")
	form.Add("Attributes.entry.2.key", "FilterPolicy")
	form.Add("Attributes.entry.2.value", "{\"filter\": [\"policy\"]}")

	cqr := &SubscribeRequest{
		Attributes: SubscriptionAttributes{},
	}
	cqr.SetAttributesFromForm(form)

	assert.True(t, cqr.Attributes.RawMessageDelivery)
	assert.Equal(t, FilterPolicy{"filter": []string{"policy"}}, cqr.Attributes.FilterPolicy)
}

func TestSubscribeRequest_SetAttributesFromForm_skips_invalid_values(t *testing.T) {
	form := url.Values{}
	form.Add("Attributes.entry.1.key", "RawMessageDelivery")
	form.Add("Attributes.entry.1.value", "garbage")
	form.Add("Attributes.entry.2.key", "FilterPolicy")
	form.Add("Attributes.entry.2.value", "also-garbage")

	cqr := &SubscribeRequest{
		Attributes: SubscriptionAttributes{},
	}
	cqr.SetAttributesFromForm(form)

	assert.False(t, cqr.Attributes.RawMessageDelivery)
	assert.Equal(t, FilterPolicy(nil), cqr.Attributes.FilterPolicy)
}

func TestSubscribeRequest_SetAttributesFromForm_stops_if_attributes_not_numbered_sequentially(t *testing.T) {
	form := url.Values{}
	form.Add("Attributes.entry.2.key", "RawMessageDelivery")
	form.Add("Attributes.entry.2.value", "garbage")
	form.Add("Attributes.entry.3.key", "FilterPolicy")
	form.Add("Attributes.entry.3.value", "also-garbage")

	cqr := &SubscribeRequest{
		Attributes: SubscriptionAttributes{},
	}
	cqr.SetAttributesFromForm(form)

	assert.False(t, cqr.Attributes.RawMessageDelivery)
	assert.Equal(t, FilterPolicy(nil), cqr.Attributes.FilterPolicy)
}

func Test_DeleteMessageBatchRequest_SetAttributesFromForm_success(t *testing.T) {
	form := url.Values{}
	form.Add("DeleteMessageBatchRequestEntry.1.Id", "message-id-1")
	form.Add("DeleteMessageBatchRequestEntry.1.ReceiptHandle", "receipt-handle-1")
	form.Add("DeleteMessageBatchRequestEntry.2.Id", "message-id-2")
	form.Add("DeleteMessageBatchRequestEntry.2.ReceiptHandle", "receipt-handle-2")
	form.Add("DeleteMessageBatchRequestEntry.3.Id", "message-id-3")
	form.Add("DeleteMessageBatchRequestEntry.3.ReceiptHandle", "receipt-handle-3")

	dmbr := &DeleteMessageBatchRequest{}
	dmbr.SetAttributesFromForm(form)

	assert.Len(t, dmbr.Entries, 3)
	assert.Equal(t, "message-id-1", dmbr.Entries[0].Id)
	assert.Equal(t, "receipt-handle-1", dmbr.Entries[0].ReceiptHandle)
	assert.Equal(t, "message-id-2", dmbr.Entries[1].Id)
	assert.Equal(t, "receipt-handle-2", dmbr.Entries[1].ReceiptHandle)
	assert.Equal(t, "message-id-3", dmbr.Entries[2].Id)
	assert.Equal(t, "receipt-handle-3", dmbr.Entries[2].ReceiptHandle)
}

func Test_DeleteMessageBatchRequest_SetAttributesFromForm_stops_at_non_sequential_keys(t *testing.T) {
	form := url.Values{}
	form.Add("DeleteMessageBatchRequestEntry.1.Id", "message-id-1")
	form.Add("DeleteMessageBatchRequestEntry.1.ReceiptHandle", "receipt-handle-1")
	form.Add("DeleteMessageBatchRequestEntry.4.Id", "message-id-2")
	form.Add("DeleteMessageBatchRequestEntry.4.ReceiptHandle", "receipt-handle-2")
	form.Add("DeleteMessageBatchRequestEntry.3.Id", "message-id-3")
	form.Add("DeleteMessageBatchRequestEntry.3.ReceiptHandle", "receipt-handle-3")

	dmbr := &DeleteMessageBatchRequest{}
	dmbr.SetAttributesFromForm(form)

	assert.Len(t, dmbr.Entries, 1)
	assert.Equal(t, "message-id-1", dmbr.Entries[0].Id)
	assert.Equal(t, "receipt-handle-1", dmbr.Entries[0].ReceiptHandle)
}

func Test_DeleteMessageBatchRequest_SetAttributesFromForm_stops_at_invalid_keys(t *testing.T) {
	form := url.Values{}
	form.Add("DeleteMessageBatchRequestEntry.1.Id", "message-id-1")
	form.Add("DeleteMessageBatchRequestEntry.1.ReceiptHandle", "receipt-handle-1")
	form.Add("INVALID_DeleteMessageBatchRequestEntry.2.Id", "message-id-2")
	form.Add("DeleteMessageBatchRequestEntry.2.ReceiptHandle", "receipt-handle-2")
	form.Add("DeleteMessageBatchRequestEntry.3.Id", "message-id-3")
	form.Add("DeleteMessageBatchRequestEntry.3.ReceiptHandle", "receipt-handle-3")

	dmbr := &DeleteMessageBatchRequest{}
	dmbr.SetAttributesFromForm(form)

	assert.Len(t, dmbr.Entries, 1)
	assert.Equal(t, "message-id-1", dmbr.Entries[0].Id)
	assert.Equal(t, "receipt-handle-1", dmbr.Entries[0].ReceiptHandle)
}

func TestPublishRequest_SetAttributesFromForm_success_concurrent(t *testing.T) {
	form := url.Values{}
	form.Add("MessageAttributes.entry.1.Name", "test1")
	form.Add("MessageAttributes.entry.1.Value.DataType", "String")
	form.Add("MessageAttributes.entry.1.Value.StringValue", "sample-string")
	form.Add("MessageAttributes.entry.2.Name", "test2")
	form.Add("MessageAttributes.entry.2.Value.DataType", "Binary")
	form.Add("MessageAttributes.entry.2.Value.BinaryValue", "YmluYXJ5LXZhbHVl")

	// if the code is not thread-safe, repeated runs increase the chance of detecting a race.
	for r := 0; r < 10; r++ {
		var wg sync.WaitGroup
		goroutineCount := 40
		// launch goroutines in parallel to simulate concurrent access.
		for g := 0; g < goroutineCount; g++ {
			wg.Add(1)
			go func() {
				defer wg.Done()
				// introduce a random delay to encourage goroutine interleaving
				time.Sleep(time.Duration(rand.Intn(5)) * time.Millisecond)
				cqr := &PublishRequest{
					MessageAttributes: make(map[string]MessageAttribute),
				}

				cqr.SetAttributesFromForm(form)

				// validate the expected DataType values
				assert.Equal(t, "String", cqr.MessageAttributes["test1"].DataType)
				assert.Equal(t, "Binary", cqr.MessageAttributes["test2"].DataType)
			}()
		}
		wg.Wait()
	}
}

func TestParseMessageAttributes(t *testing.T) {
	for _, tc := range []struct {
		description string
		values      url.Values
		keyPrefix   string
		want        map[string]MessageAttribute
	}{
		{
			description: "empty",
			values:      url.Values{},
			keyPrefix:   "foo",
			want:        nil,
		},
		{
			description: "simple",
			values: url.Values{
				"MessageAttribute.1.Name":              []string{"Attr1"},
				"MessageAttribute.1.Value.DataType":    []string{"String"},
				"MessageAttribute.1.Value.StringValue": []string{"Value1"},
				"MessageAttribute.2.Name":              []string{"Attr2"},
				"MessageAttribute.2.Value.DataType":    []string{"Binary"},
				"MessageAttribute.2.Value.BinaryValue": []string{"VmFsdWUy"},
			},
			keyPrefix: "MessageAttribute",
			want: map[string]MessageAttribute{
				"Attr1": {
					DataType:    "String",
					StringValue: "Value1",
					BinaryValue: "",
				},
				"Attr2": {
					DataType:    "Binary",
					BinaryValue: "VmFsdWUy",
				},
			},
		},
		{
			description: "attributes after empty name ignored",
			values: url.Values{
				"MessageAttribute.1.Name":              []string{""},
				"MessageAttribute.1.Value.DataType":    []string{"String"},
				"MessageAttribute.1.Value.StringValue": []string{"Value4"},
				"MessageAttribute.2.Name":              []string{"Attr2"},
				"MessageAttribute.2.Value.DataType":    []string{"Binary"},
				"MessageAttribute.2.Value.BinaryValue": []string{"VmFsdWUy"},
			},
			keyPrefix: "MessageAttribute",
			want:      nil,
		},
		{
			description: "attributes after missing number ignored",
			values: url.Values{
				// Note starting from 2
				"MessageAttribute.2.Name":              []string{"Attr2"},
				"MessageAttribute.2.Value.DataType":    []string{"Binary"},
				"MessageAttribute.2.Value.BinaryValue": []string{"VmFsdWUy"},
			},
			keyPrefix: "MessageAttribute",
			want:      nil,
		},
		{
			description: "empty DataType ignored",
			values: url.Values{
				"MessageAttribute.1.Name":              []string{"Attr4"},
				"MessageAttribute.1.Value.DataType":    []string{""},
				"MessageAttribute.1.Value.StringValue": []string{"Value4"},
			},
			keyPrefix: "MessageAttribute",
			want:      nil,
		},
	} {
		t.Run(tc.description, func(t *testing.T) {
			got := parseMessageAttributes(tc.values, tc.keyPrefix)
			assert.Equal(t, tc.want, got)
		})
	}
}
