# LocalStack Resource Provider Scaffolding v1
import os

import pytest
from botocore.exceptions import ClientError

from localstack.testing.aws.util import is_aws_cloud
from localstack.testing.pytest import markers
from localstack.utils.strings import short_uid


class TestBasicCRD:
    @markers.aws.validated
    def test_black_box(self, deploy_cfn_template, aws_client, snapshot):
        """
        Simple test that
        - deploys a stack containing the resource
        - verifies that the resource has been created correctly by querying the service directly
        - deletes the stack ensuring that the delete operation has been implemented correctly
        - verifies that the resource no longer exists by querying the service directly
        """
        user_name = f"test-user-{short_uid()}"
        snapshot.add_transformer(snapshot.transform.regex(user_name, "<user-name>"))
        snapshot.add_transformer(snapshot.transform.key_value("UserId", "user-id"))

        stack = deploy_cfn_template(
            template_path=os.path.join(
                os.path.dirname(__file__),
                "templates/user_basic.yaml",
            ),
            parameters={"CustomUserName": user_name},
        )
        snapshot.match("stack-outputs", stack.outputs)
        snapshot.match("describe-resource", aws_client.iam.get_user(UserName=user_name))

        # verify that the delete operation works
        stack.destroy()

        # fetch the resource again and assert that it no longer exists
        with pytest.raises(ClientError):
            aws_client.iam.get_user(UserName=user_name)

    @markers.aws.validated
    def test_autogenerated_values(self, aws_client, deploy_cfn_template, snapshot):
        stack = deploy_cfn_template(
            template_path=os.path.join(
                os.path.dirname(__file__),
                "templates/user_basic_autogenerated.yaml",
            ),
        )
        snapshot.match("stack_outputs", stack.outputs)
        user_name = stack.outputs[
            "MyRef"
        ]  # Captured example: 'stack-9126a688-MyResource-123WYN8UFFGZM'
        snapshot.add_transformer(snapshot.transform.regex(user_name, "<user-name>"))
        snapshot.add_transformer(snapshot.transform.key_value("UserId", "user-id"))

        # verify resource has been correctly deployed with the autogenerated field
        response = aws_client.iam.get_user(UserName=user_name)
        snapshot.match("autogenerated-get-user", response)

        # check the auto-generated pattern
        assert stack.stack_name in user_name
        assert "MyResource" in user_name

    @pytest.mark.skip_snapshot_verify
    @markers.aws.validated
    def test_getatt(self, snapshot, deploy_cfn_template, aws_client):
        user_name = f"test-user-{short_uid()}"
        snapshot.add_transformer(snapshot.transform.regex(user_name, "<user-name>"))
        snapshot.add_transformer(snapshot.transform.key_value("UserId", "user-id"))

        stack = deploy_cfn_template(
            template_path=os.path.join(
                os.path.dirname(__file__),
                "templates/user_getatt.yaml",
            ),
            parameters={"CustomUserName": user_name},
        )
        snapshot.match("stack-outputs", stack.outputs)
        user_details = aws_client.iam.get_user(UserName=user_name)
        snapshot.match("describe-resource", user_details)

        stack_resource = aws_client.cloudformation.describe_stack_resource(
            StackName=stack.stack_name, LogicalResourceId="MyResource"
        )
        snapshot.match("stack_resource", stack_resource)

        assert user_details["User"]["Arn"]
        assert user_details["User"]["Arn"] == stack.outputs["GetAttArn"]

        # verify that the delete operation works
        stack.destroy()

        # fetch the resource again and assert that it no longer exists
        with pytest.raises(ClientError):
            aws_client.iam.get_user(UserName=user_name)


@pytest.mark.skipif(condition=not is_aws_cloud(), reason="Not working yet")
class TestUpdates:
    @markers.aws.validated
    def test_update_without_replacement(self, deploy_cfn_template, aws_client, snapshot):
        """
        Test an UPDATE of a simple property that does not require replacing the entire resource.
        Check out the official resource documentation at https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-template-resource-type-ref.html to see if a property needs replacement
        """
        user_name = f"test-user-{short_uid()}"
        updated_user_name = f"{user_name}-updated"
        snapshot.add_transformer(snapshot.transform.regex(user_name, "<user-name>"))
        snapshot.add_transformer(snapshot.transform.key_value("UserId", "user-id"))

        # create stack
        stack = deploy_cfn_template(
            template_path=os.path.join(
                os.path.dirname(__file__),
                "templates/user_update.yaml",
            ),
            parameters={"AttributeValue": user_name},
        )
        snapshot.match("stack-outputs-before-update", stack.outputs)

        # verify actual resource deployment
        response = aws_client.iam.get_user(UserName=user_name)
        with pytest.raises(ClientError):
            aws_client.iam.get_user(UserName=updated_user_name)
        snapshot.match("describe-resource-before-update", response)

        # update the stack
        stack_updated = deploy_cfn_template(
            stack_name=stack.stack_name,
            template_path=os.path.join(
                os.path.dirname(__file__),
                "templates/user_update.yaml",
            ),
            parameters={"AttributeValue": updated_user_name},
            is_update=True,
        )

        # verify updated resource deployment
        response = aws_client.iam.get_user(UserName=updated_user_name)
        with pytest.raises(ClientError):
            aws_client.iam.get_user(UserName=user_name)

        snapshot.match("describe-resource-after-update", response)
        snapshot.match("stack-outputs-after-update", stack_updated.outputs)
