"""Tests for ARN pattern matching."""

import boto3
import pytest

from arnmatch import arnmatch


def test_acm():
    result = arnmatch(
        "arn:aws:acm:us-east-1:012345678901:certificate/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
    )
    assert result.resource_type == "certificate"
    assert result.attributes["CertificateId"] == "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
    assert result.aws_sdk_services == ["acm"]
    assert result.aws_sdk_service == "acm"
    assert result.cloudformation_resource == "AWS::CertificateManager::Certificate"


def test_apigateway():
    # v1 REST API (default)
    result = arnmatch("arn:aws:apigateway:us-east-1::/restapis/abc123def4")
    assert result.resource_type == "rest-api"
    assert result.attributes["RestApiId"] == "abc123def4"
    assert result.aws_sdk_service == "apigateway"

    # v2 HTTP API (override)
    result = arnmatch("arn:aws:apigateway:us-east-1::/apis/abc123def4")
    assert result.resource_type == "api"
    assert result.aws_sdk_service == "apigatewayv2"


def test_athena():
    result = arnmatch("arn:aws:athena:us-east-1:012345678901:workgroup/workgroup1")
    assert result.resource_type == "workgroup"
    assert result.attributes["WorkGroupName"] == "workgroup1"


def test_autoscaling():
    result = arnmatch(
        "arn:aws:autoscaling:us-east-1:012345678901:autoScalingGroup:aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee:autoScalingGroupName/asg1"
    )
    assert result.resource_type == "autoscaling-group"
    assert result.attributes["GroupId"] == "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
    assert result.attributes["GroupFriendlyName"] == "asg1"


def test_backup():
    result = arnmatch("arn:aws:backup:us-east-1:012345678901:backup-vault:vault1")
    assert result.resource_type == "backup-vault"
    assert result.attributes["BackupVaultName"] == "vault1"


def test_cloudformation():
    result = arnmatch(
        "arn:aws:cloudformation:us-east-1:012345678901:stack/stack1/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
    )
    assert result.resource_type == "stack"
    assert result.attributes["StackName"] == "stack1"
    assert result.attributes["Id"] == "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"


def test_cloudfront():
    result = arnmatch("arn:aws:cloudfront::012345678901:distribution/ABCDEFGHIJKLMN")
    assert result.resource_type == "distribution"
    assert result.attributes["DistributionId"] == "ABCDEFGHIJKLMN"


def test_cloudtrail():
    result = arnmatch("arn:aws:cloudtrail:us-east-1:012345678901:trail/trailname1")
    assert result.resource_type == "trail"
    assert result.attributes["TrailName"] == "trailname1"


def test_cloudwatch():
    result = arnmatch(
        "arn:aws:cloudwatch:us-east-1:012345678901:alarm:CPU Utilization - High Warning - service-production-1"
    )
    assert result.resource_type == "alarm"
    assert (
        result.attributes["AlarmName"]
        == "CPU Utilization - High Warning - service-production-1"
    )
    # cloudwatch is a manual override (endpointPrefix is 'monitoring')
    assert result.aws_sdk_services == ["cloudwatch"]


def test_codebuild():
    result = arnmatch("arn:aws:codebuild:us-east-1:012345678901:project/build_image")
    assert result.resource_type == "project"
    assert result.attributes["ProjectName"] == "build_image"


def test_codecommit():
    result = arnmatch("arn:aws:codecommit:us-east-1:012345678901:repository1")
    assert result.resource_type == "repository"
    assert result.attributes["RepositoryName"] == "repository1"


def test_codepipeline():
    result = arnmatch("arn:aws:codepipeline:us-east-1:012345678901:deploy_pipeline")
    assert result.resource_type == "pipeline"
    assert result.attributes["PipelineName"] == "deploy_pipeline"


def test_datasync():
    result = arnmatch(
        "arn:aws:datasync:us-east-1:012345678901:task/task-0123456789abcdef0"
    )
    assert result.resource_type == "task"
    assert result.attributes["TaskId"] == "task-0123456789abcdef0"


def test_dynamodb():
    # table (default)
    result = arnmatch("arn:aws:dynamodb:us-east-1:012345678901:table/table1")
    assert result.resource_type == "table"
    assert result.attributes["TableName"] == "table1"
    assert result.aws_sdk_service == "dynamodb"
    assert result.cloudformation_resource == "AWS::DynamoDB::Table"

    # stream (override)
    result = arnmatch(
        "arn:aws:dynamodb:us-east-1:012345678901:table/table1/stream/2024-01-01T00:00:00.000"
    )
    assert result.resource_type == "stream"
    assert result.aws_sdk_service == "dynamodbstreams"


def test_ec2():
    result = arnmatch("arn:aws:ec2:us-east-1:012345678901:instance/i-0123456789abcdef0")
    assert result.resource_type == "instance"
    assert result.attributes["InstanceId"] == "i-0123456789abcdef0"

    result = arnmatch("arn:aws:ec2:us-east-1:012345678901:volume/vol-0123456789abcdef0")
    assert result.resource_type == "volume"
    assert result.attributes["VolumeId"] == "vol-0123456789abcdef0"

    result = arnmatch(
        "arn:aws:ec2:us-east-1:012345678901:snapshot/snap-0123456789abcdef0"
    )
    assert result.resource_type == "snapshot"
    assert result.attributes["SnapshotId"] == "snap-0123456789abcdef0"

    result = arnmatch("arn:aws:ec2:us-east-1:012345678901:image/ami-0123456789abcdef0")
    assert result.resource_type == "image"
    assert result.attributes["ImageId"] == "ami-0123456789abcdef0"

    result = arnmatch(
        "arn:aws:ec2:us-east-1:012345678901:elastic-ip/eipalloc-0123456789abcdef0"
    )
    assert result.resource_type == "elastic-ip"
    assert result.attributes["AllocationId"] == "eipalloc-0123456789abcdef0"

    result = arnmatch(
        "arn:aws:ec2:us-east-1:012345678901:natgateway/nat-0123456789abcdef0"
    )
    assert result.resource_type == "nat-gateway"
    assert result.attributes["NatGatewayId"] == "nat-0123456789abcdef0"

    result = arnmatch(
        "arn:aws:ec2:us-east-1:012345678901:vpc-endpoint/vpce-0123456789abcdef0"
    )
    assert result.resource_type == "vpc-endpoint"
    assert result.attributes["VpcEndpointId"] == "vpce-0123456789abcdef0"

    result = arnmatch(
        "arn:aws:ec2:us-east-1:012345678901:launch-template/lt-0123456789abcdef0"
    )
    assert result.resource_type == "launch-template"
    assert result.attributes["LaunchTemplateId"] == "lt-0123456789abcdef0"

    result = arnmatch(
        "arn:aws:ec2:us-east-1:012345678901:reserved-instances/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
    )
    assert result.resource_type == "reserved-instances"
    assert result.attributes["ReservationId"] == "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"

    result = arnmatch(
        "arn:aws:ec2:us-east-1:012345678901:spot-instances-request/sir-abcd1234"
    )
    assert result.resource_type == "spot-instances-request"
    assert result.attributes["SpotInstanceRequestId"] == "sir-abcd1234"


def test_ecr():
    result = arnmatch("arn:aws:ecr:us-east-1:012345678901:repository/web-service")
    assert result.resource_type == "repository"
    assert result.attributes["RepositoryName"] == "web-service"


def test_eks():
    result = arnmatch("arn:aws:eks:us-east-1:012345678901:cluster/c1")
    assert result.resource_type == "cluster"
    assert result.attributes["ClusterName"] == "c1"


def test_elasticache():
    result = arnmatch(
        "arn:aws:elasticache:us-east-1:012345678901:cluster:redis-cluster-node-001"
    )
    assert result.resource_type == "cluster"
    assert result.attributes["CacheClusterId"] == "redis-cluster-node-001"

    result = arnmatch(
        "arn:aws:elasticache:us-east-1:012345678901:parametergroup:redis-cluster-params-redis7"
    )
    assert result.resource_type == "parameter-group"
    assert result.attributes["CacheParameterGroupName"] == "redis-cluster-params-redis7"

    result = arnmatch(
        "arn:aws:elasticache:us-east-1:012345678901:replicationgroup:redis-repl-group1"
    )
    assert result.resource_type == "replication-group"
    assert result.attributes["ReplicationGroupId"] == "redis-repl-group1"

    result = arnmatch(
        "arn:aws:elasticache:us-east-1:012345678901:reserved-instance:reserved-node-prod1"
    )
    assert result.resource_type == "reserved-instance"
    assert result.attributes["ReservedCacheNodeId"] == "reserved-node-prod1"

    result = arnmatch(
        "arn:aws:elasticache:us-east-1:012345678901:subnetgroup:cache-subnet-group1"
    )
    assert result.resource_type == "subnet-group"
    assert result.attributes["CacheSubnetGroupName"] == "cache-subnet-group1"

    result = arnmatch("arn:aws:elasticache:us-east-1:012345678901:user:default")
    assert result.resource_type == "user"
    assert result.attributes["UserId"] == "default"


def test_elasticfilesystem():
    result = arnmatch(
        "arn:aws:elasticfilesystem:us-east-1:012345678901:file-system/fs-01234567"
    )
    assert result.resource_type == "file-system"
    assert result.attributes["FileSystemId"] == "fs-01234567"
    # elasticfilesystem maps to efs via metadata
    assert result.aws_sdk_services == ["efs"]


def test_elasticloadbalancing():
    # Classic LB (override)
    result = arnmatch(
        "arn:aws:elasticloadbalancing:us-east-1:012345678901:loadbalancer/a0123456789abcdef0123456789abcde"
    )
    assert result.resource_type == "loadbalancer"
    assert result.attributes["LoadBalancerName"] == "a0123456789abcdef0123456789abcde"
    assert result.aws_sdk_service == "elb"

    # ALB (default)
    result = arnmatch(
        "arn:aws:elasticloadbalancing:us-east-1:012345678901:loadbalancer/app/alb-application-lb-name/0123456789abcdef"
    )
    assert result.resource_type == "loadbalancer-app"
    assert result.attributes["LoadBalancerName"] == "alb-application-lb-name"
    assert result.attributes["LoadBalancerId"] == "0123456789abcdef"
    assert result.aws_sdk_service == "elbv2"

    # NLB (default)
    result = arnmatch(
        "arn:aws:elasticloadbalancing:us-east-1:012345678901:loadbalancer/net/nlb-network-load-balancer/0123456789abcdef"
    )
    assert result.resource_type == "loadbalancer-net"
    assert result.attributes["LoadBalancerName"] == "nlb-network-load-balancer"
    assert result.attributes["LoadBalancerId"] == "0123456789abcdef"
    assert result.aws_sdk_service == "elbv2"

    # Target group (default)
    result = arnmatch(
        "arn:aws:elasticloadbalancing:us-east-1:012345678901:targetgroup/target-grp-1/0123456789abcdef"
    )
    assert result.resource_type == "target-group"
    assert result.attributes["TargetGroupName"] == "target-grp-1"
    assert result.attributes["TargetGroupId"] == "0123456789abcdef"
    # elasticloadbalancing maps to multiple SDK clients
    assert result.aws_sdk_services == ["elb", "elbv2"]
    assert result.aws_sdk_service == "elbv2"


def test_es():
    result = arnmatch("arn:aws:es:us-east-1:012345678901:domain/search-domain-prod")
    assert result.resource_type == "domain"
    assert result.attributes["DomainName"] == "search-domain-prod"


def test_events():
    result = arnmatch("arn:aws:events:us-east-1:012345678901:event-bus/default")
    assert result.resource_type == "event-bus"
    assert result.attributes["EventBusName"] == "default"

    result = arnmatch("arn:aws:events:us-east-1:012345678901:rule/ScheduledEventRule01")
    assert result.resource_type == "rule-on-default-event-bus"
    assert result.attributes["RuleName"] == "ScheduledEventRule01"


def test_guardduty():
    result = arnmatch(
        "arn:aws:guardduty:us-east-1:012345678901:detector/0123456789abcdef0123456789abcdef"
    )
    assert result.resource_type == "detector"
    assert result.attributes["DetectorId"] == "0123456789abcdef0123456789abcdef"


def test_iam():
    result = arnmatch("arn:aws:iam::012345678901:user/admin")
    assert result.resource_type == "user"
    assert result.attributes["AwsUserName"] == "admin"
    assert result.cloudformation_resource == "AWS::IAM::User"

    result = arnmatch("arn:aws:iam::012345678901:role/lambda-execution-role")
    assert result.resource_type == "iam-role"
    assert result.attributes["RoleName"] == "lambda-execution-role"
    # Note: iam-role has empty cloudformation in YAML (data issue to be fixed separately)
    # assert result.cloudformation_resource == "AWS::IAM::Role"

    result = arnmatch("arn:aws:iam::012345678901:policy/custom-policy")
    assert result.resource_type == "policy"
    assert result.attributes["PolicyNameWithPath"] == "custom-policy"

    result = arnmatch("arn:aws:iam::012345678901:group/developers")
    assert result.resource_type == "group"
    assert result.attributes["GroupNameWithPath"] == "developers"
    assert result.cloudformation_resource == "AWS::IAM::Group"

    result = arnmatch("arn:aws:iam::012345678901:instance-profile/ec2-profile")
    assert result.resource_type == "instance-profile"
    assert result.attributes["InstanceProfileNameWithPath"] == "ec2-profile"
    assert result.cloudformation_resource == "AWS::IAM::InstanceProfile"


def test_kms():
    result = arnmatch(
        "arn:aws:kms:us-east-1:012345678901:key/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
    )
    assert result.resource_type == "key"
    assert result.attributes["KeyId"] == "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"


def test_lambda():
    result = arnmatch(
        "arn:aws:lambda:us-east-1:012345678901:function:ProcessDataHandler"
    )
    assert result.resource_type == "function"
    assert result.attributes["FunctionName"] == "ProcessDataHandler"
    assert result.aws_sdk_services == ["lambda"]
    assert result.cloudformation_resource == "AWS::Lambda::Function"


def test_logs():
    result = arnmatch(
        "arn:aws:logs:us-east-1:012345678901:log-group:/aws/lambda/function-logs"
    )
    assert result.resource_type == "log-group"
    assert result.attributes["LogGroupName"] == "/aws/lambda/function-logs"


def test_rds():
    result = arnmatch("arn:aws:rds:us-east-1:012345678901:cluster:database-cluster-1")
    assert result.resource_type == "cluster"
    assert result.attributes["DbClusterInstanceName"] == "database-cluster-1"

    result = arnmatch("arn:aws:rds:us-east-1:012345678901:cluster-snapshot:snap001")
    assert result.resource_type == "cluster-snapshot"
    assert result.attributes["ClusterSnapshotName"] == "snap001"

    result = arnmatch("arn:aws:rds:us-east-1:012345678901:db:database-instance-1")
    assert result.resource_type == "db"
    assert result.attributes["DbInstanceName"] == "database-instance-1"

    result = arnmatch("arn:aws:rds:us-east-1:012345678901:ri:reserved01")
    assert result.resource_type == "ri"
    assert result.attributes["ReservedDbInstanceName"] == "reserved01"

    result = arnmatch(
        "arn:aws:rds:us-east-1:012345678901:snapshot:final-database-backup-01234567"
    )
    assert result.resource_type == "snapshot"
    assert result.attributes["SnapshotName"] == "final-database-backup-01234567"
    # rds maps to multiple SDK clients (rds, docdb, neptune share ARN format)
    assert result.aws_sdk_services == ["rds", "docdb", "neptune"]


def test_route53():
    result = arnmatch(
        "arn:aws:route53:::healthcheck/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
    )
    assert result.resource_type == "healthcheck"
    assert result.attributes["Id"] == "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"

    result = arnmatch("arn:aws:route53:::hostedzone/Z0123456789ABCDEFGHIJ")
    assert result.resource_type == "hostedzone"
    assert result.attributes["Id"] == "Z0123456789ABCDEFGHIJ"


def test_s3():
    # bucket (default)
    result = arnmatch("arn:aws:s3:::example-bucket-01")
    assert result.resource_type == "bucket"
    assert result.attributes["BucketName"] == "example-bucket-01"
    assert result.aws_sdk_services == ["s3", "s3control"]
    assert result.aws_sdk_service == "s3"
    assert result.cloudformation_resource == "AWS::S3::Bucket"

    # accesspoint (override)
    result = arnmatch("arn:aws:s3:us-east-1:012345678901:accesspoint/my-access-point")
    assert result.resource_type == "access-point"
    assert result.aws_sdk_service == "s3control"
    assert result.cloudformation_resource == "AWS::S3::AccessPoint"


def test_secretsmanager():
    result = arnmatch(
        "arn:aws:secretsmanager:us-east-1:012345678901:secret:/app/secrets/service-name/production-AbCdEf"
    )
    assert result.resource_type == "secret"
    assert result.attributes["SecretId"] == "/app/secrets/service-name/production-AbCdEf"


def test_sns():
    result = arnmatch("arn:aws:sns:us-east-1:012345678901:topic1")
    assert result.resource_type == "topic"
    assert result.attributes["TopicName"] == "topic1"
    assert result.cloudformation_resource == "AWS::SNS::Topic"


def test_sqs():
    result = arnmatch("arn:aws:sqs:us-east-1:012345678901:processing-queue-1")
    assert result.resource_type == "queue"
    assert result.attributes["QueueName"] == "processing-queue-1"
    assert result.cloudformation_resource == "AWS::SQS::Queue"


def test_ssm():
    result = arnmatch("arn:aws:ssm:us-east-1:012345678901:parameter/config_val")
    assert result.resource_type == "parameter"
    assert result.attributes["ParameterNameWithoutLeadingSlash"] == "config_val"


def test_wafv2():
    result = arnmatch(
        "arn:aws:wafv2:us-east-1:012345678901:global/webacl/WebACL-for-CloudFront-01/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
    )
    assert result.resource_type == "webacl"
    assert result.attributes["Scope"] == "global"
    assert result.attributes["Name"] == "WebACL-for-CloudFront-01"
    assert result.attributes["Id"] == "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"

    result = arnmatch(
        "arn:aws:wafv2:us-east-1:012345678901:regional/webacl/webacl-production-acl/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
    )
    assert result.resource_type == "webacl"
    assert result.attributes["Scope"] == "regional"
    assert result.attributes["Name"] == "webacl-production-acl"
    assert result.attributes["Id"] == "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"


class TestTaggingResource:
    """Tests for tagging_resource field."""

    def test_ec2_instance_has_tagging(self):
        """EC2 instance has both CFN and tagging."""
        result = arnmatch("arn:aws:ec2:us-east-1:012345678901:instance/i-0123456789abcdef0")
        assert result.cloudformation_resource == "AWS::EC2::Instance"
        assert result.tagging_resource == "AWS::EC2::Instance"

    def test_lambda_function_has_tagging(self):
        """Lambda function has both CFN and tagging."""
        result = arnmatch("arn:aws:lambda:us-east-1:012345678901:function:my-function")
        assert result.cloudformation_resource == "AWS::Lambda::Function"
        assert result.tagging_resource == "AWS::Lambda::Function"

    def test_s3_bucket_has_tagging(self):
        """S3 bucket has both CFN and tagging."""
        result = arnmatch("arn:aws:s3:::my-bucket")
        assert result.cloudformation_resource == "AWS::S3::Bucket"
        assert result.tagging_resource == "AWS::S3::Bucket"

    def test_kafka_cluster(self):
        """Kafka cluster has different CFN (MSK) vs tagging (Kafka) service names."""
        result = arnmatch(
            "arn:aws:kafka:us-east-1:012345678901:cluster/my-cluster/12345678-1234-1234-1234-123456789012"
        )
        assert result.resource_type == "cluster"
        assert result.attributes["ClusterName"] == "my-cluster"
        assert result.aws_sdk_service == "kafka"
        # CFN uses MSK namespace, tagging uses Kafka namespace
        assert result.cloudformation_resource == "AWS::MSK::Cluster"
        assert result.tagging_resource == "AWS::Kafka::Cluster"

    def test_kafka_topic_no_tagging(self):
        """Kafka topic has no CFN or tagging (sub-resource)."""
        result = arnmatch(
            "arn:aws:kafka:us-east-1:012345678901:topic/my-cluster/12345678-1234-1234-1234-123456789012/my-topic"
        )
        assert result.resource_type == "topic"
        assert result.attributes["TopicName"] == "my-topic"
        assert result.cloudformation_resource is None
        assert result.tagging_resource is None

    def test_kafka_configuration_cfn_only(self):
        """Kafka configuration has CFN but no tagging."""
        result = arnmatch(
            "arn:aws:kafka:us-east-1:012345678901:configuration/my-config/12345678-1234-1234-1234-123456789012"
        )
        assert result.resource_type == "configuration"
        assert result.cloudformation_resource == "AWS::MSK::Configuration"
        assert result.tagging_resource is None

    def test_kafka_replicator(self):
        """Kafka replicator has both CFN and tagging as MSK."""
        result = arnmatch(
            "arn:aws:kafka:us-east-1:012345678901:replicator/my-replicator/12345678-1234-1234-1234-123456789012"
        )
        assert result.resource_type == "replicator"
        assert result.cloudformation_resource == "AWS::MSK::Replicator"
        assert result.tagging_resource == "AWS::MSK::Replicator"

    def test_ec2_instance_event_window_tagging_only(self):
        """EC2 instance-event-window has tagging but no CFN."""
        result = arnmatch(
            "arn:aws:ec2:us-east-1:012345678901:instance-event-window/iew-0123456789abcdef0"
        )
        assert result.resource_type == "instance-event-window"
        assert result.cloudformation_resource is None
        assert result.tagging_resource == "AWS::EC2::InstanceEventWindow"

    def test_cloudfront_distribution(self):
        """CloudFront distribution has both CFN and tagging."""
        result = arnmatch("arn:aws:cloudfront::012345678901:distribution/ABCDEFGHIJKLMN")
        assert result.cloudformation_resource == "AWS::CloudFront::Distribution"
        assert result.tagging_resource == "AWS::CloudFront::Distribution"

    def test_dynamodb_table(self):
        """DynamoDB table has both CFN and tagging."""
        result = arnmatch("arn:aws:dynamodb:us-east-1:012345678901:table/my-table")
        assert result.cloudformation_resource == "AWS::DynamoDB::Table"
        assert result.tagging_resource == "AWS::DynamoDB::Table"


class TestClient:
    """Tests for ARN.client() method."""

    def test_client_returns_correct_service(self):
        """Test client() returns a client for the correct service."""
        result = arnmatch(
            "arn:aws:lambda:us-east-1:012345678901:function:my-function"
        )
        client = result.client()
        assert client.meta.service_model.service_name == "lambda"

    def test_client_uses_provided_session(self):
        """Test client() uses the provided session."""
        session = boto3.Session()
        result = arnmatch("arn:aws:s3:::my-bucket")
        client = result.client(session=session)
        assert client.meta.service_model.service_name == "s3"

    def test_client_raises_when_no_sdk_mapping(self):
        """Test client() raises ValueError when no SDK service mapping exists."""
        # 'a4b' (Alexa for Business) has no SDK mapping
        result = arnmatch("arn:aws:a4b:us-east-1:012345678901:address-book/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee")

        with pytest.raises(ValueError, match="No SDK service mapping"):
            result.client()
