import boto3
import pytest

from moto import mock_aws


@pytest.mark.parametrize("wildcard", ["All", ".*"])
@mock_aws
def test_message_attributes_should_not_include_system_attributes(wildcard):
    """
    Test that receiving a message with AttributeNames=['All'] or AttributeNames=['.*']
    should NOT return empty MessageAttributes for system attributes.
    Both "All" and ".*" are equivalent per the AWS spec:
    https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_ReceiveMessage.html
    """
    client = boto3.client("sqs", region_name="us-east-1")

    # Create queue
    queue_url = client.create_queue(QueueName="test-queue")["QueueUrl"]

    # Send a message WITHOUT any message attributes
    client.send_message(QueueUrl=queue_url, MessageBody="Hello from app startup!")

    # Receive the message with All system attributes and All message attributes.
    # AttributeNames only accepts "All" or specific names — ".*" is not valid there.
    response = client.receive_message(
        QueueUrl=queue_url,
        AttributeNames=["All"],
        MessageAttributeNames=[wildcard],
        MaxNumberOfMessages=1,
    )

    # Check that the message was received
    assert "Messages" in response
    assert len(response["Messages"]) == 1

    message = response["Messages"][0]

    # System attributes should be in Attributes
    assert "Attributes" in message
    assert "SenderId" in message["Attributes"]
    assert "SentTimestamp" in message["Attributes"]
    assert "ApproximateReceiveCount" in message["Attributes"]
    assert "ApproximateFirstReceiveTimestamp" in message["Attributes"]

    # MessageAttributes should either be absent or be an empty dict
    # It should NOT contain empty objects for system attributes
    if "MessageAttributes" in message:
        # MessageAttributes should be empty since we didn't send any
        assert message["MessageAttributes"] == {}, (
            f"MessageAttributes should be empty, but got: {message['MessageAttributes']}"
        )


@mock_aws
def test_message_attributes_work_correctly_when_present():
    """
    Test that MessageAttributes work correctly when actual message attributes are sent.
    """
    client = boto3.client("sqs", region_name="us-east-1")

    # Create queue
    queue_url = client.create_queue(QueueName="test-queue")["QueueUrl"]

    # Send a message WITH message attributes
    client.send_message(
        QueueUrl=queue_url,
        MessageBody="Hello",
        MessageAttributes={
            "Author": {"StringValue": "John Doe", "DataType": "String"},
            "Priority": {"StringValue": "1", "DataType": "Number"},
        },
    )

    # Receive the message with All attributes
    response = client.receive_message(
        QueueUrl=queue_url,
        AttributeNames=["All"],
        MessageAttributeNames=["All"],
        MaxNumberOfMessages=1,
    )

    message = response["Messages"][0]

    # Both Attributes and MessageAttributes should be present
    assert "Attributes" in message
    assert "MessageAttributes" in message

    # MessageAttributes should only contain the custom attributes we sent
    assert set(message["MessageAttributes"].keys()) == {"Author", "Priority"}
    assert message["MessageAttributes"]["Author"]["StringValue"] == "John Doe"
    assert message["MessageAttributes"]["Priority"]["StringValue"] == "1"

    # Attributes should contain system attributes, NOT message attributes
    assert "SenderId" in message["Attributes"]
    assert "SentTimestamp" in message["Attributes"]
    # System attributes should NOT be in MessageAttributes
    assert "SenderId" not in message["MessageAttributes"]
    assert "SentTimestamp" not in message["MessageAttributes"]


@mock_aws
def test_no_empty_message_attributes_without_all_parameter():
    """
    Test that MessageAttributes is not present when AttributeNames is not specified.
    """
    client = boto3.client("sqs", region_name="us-east-1")

    # Create queue
    queue_url = client.create_queue(QueueName="test-queue")["QueueUrl"]

    # Send a message WITHOUT any message attributes
    client.send_message(QueueUrl=queue_url, MessageBody="Hello")

    # Receive the message without AttributeNames or MessageAttributeNames
    response = client.receive_message(QueueUrl=queue_url, MaxNumberOfMessages=1)

    message = response["Messages"][0]

    # MessageAttributes should not be in the response
    assert "MessageAttributes" not in message


@mock_aws
def test_message_attributes_with_wildcards():
    client = boto3.client("sqs", region_name="us-east-1")
    queue_url = client.create_queue(QueueName="test-queue")["QueueUrl"]

    message_attributes = {
        "Custom1": {"StringValue": "Value1", "DataType": "String"},
        "Custom2": {"StringValue": "Value2", "DataType": "String"},
        "Other": {"StringValue": "OtherValue", "DataType": "String"},
    }

    client.send_message(
        QueueUrl=queue_url, MessageBody="test", MessageAttributes=message_attributes
    )

    # Test ".*" wildcard
    resp = client.receive_message(
        QueueUrl=queue_url, MessageAttributeNames=[".*"], MaxNumberOfMessages=1
    )
    received_attributes = resp["Messages"][0].get("MessageAttributes", {})
    assert "Custom1" in received_attributes
    assert "Custom2" in received_attributes
    assert "Other" in received_attributes

    # Test prefix wildcard
    client.send_message(
        QueueUrl=queue_url, MessageBody="test", MessageAttributes=message_attributes
    )
    resp = client.receive_message(
        QueueUrl=queue_url, MessageAttributeNames=["Custom.*"], MaxNumberOfMessages=1
    )
    received_attributes = resp["Messages"][0].get("MessageAttributes", {})
    assert "Custom1" in received_attributes
    assert "Custom2" in received_attributes
    assert "Other" not in received_attributes
