# Copyright (c) 2019 CloudZero - ALL RIGHTS RESERVED - PROPRIETARY AND CONFIDENTIAL
# Unauthorized copying of this file and/or project, via any medium is strictly prohibited.
# Direct all questions to legal@cloudzero.com
import re

from czid.common.service_types import SERVICE_TRANSFORMS

ARN_CAPTURE_REGEX = re.compile(r'^arn:(?:aws|aws-cn|aws-us-gov):([a-z0-9-]+):'
                               r'((?:[a-z0-9-]*)|global):(\d{12}|aws)*:(.+$)$')

ARN2_CAPTURE_REGEX = re.compile(r'^arn:(?:aws|aws-cn|aws-us-gov):([a-z0-9-]+):'
                                r'(\d{12}|aws)*:((?:[a-z0-9-]*)|global):(.+$)$')


def get_account_id_from_arn(arn):
    """
    Get Account ID from ARN

    >>> get_account_id_from_arn('arn:aws:ec2:us-east-1:526216611803:instance/i-0ebaff919fe99b7a5')
    '526216611803'

    >>> get_account_id_from_arn('arn:aws:lambda:us-east-1:998146006915:function:configure-check')
    '998146006915'

    >>> get_account_id_from_arn('arn:aws:iam::465007870756:role/cloudzero-reactor-access')
    '465007870756'

    Args:
        arn:

    Returns:
        str

    """
    try:
        account_id = arn.split(':')[4]
        return len(account_id) == 12 and account_id
    except (IndexError, AttributeError):
        raise ValueError(f'ARN {arn} appears invalid')


def get_region_from_arn(arn):
    """
    Get the resource type from an ARN

    >>> get_region_from_arn('arn:aws:ec2:us-east-1:526216611803:instance/i-0ebaff919fe99b7a5')
    'us-east-1'

    >>> get_region_from_arn('arn:aws:sts::123456789012:assumed-role/OrgAccessRole/aws-sdk-js-1513742739882')

    Args:
        arn:

    Returns:
        str

    """
    try:
        region = arn.split(':')[3]
        return region or None
    except (IndexError, AttributeError):
        raise ValueError(f'ARN {arn} appears invalid')


def get_arn_components(arn):
    arn_match = ARN_CAPTURE_REGEX.fullmatch(arn)
    if not arn_match:
        # Some ARNS (like client-vpn) have the account ID and region swapped
        arn_match = ARN2_CAPTURE_REGEX.fullmatch(arn)
        if not arn_match or arn_match.lastindex != 4:
            raise ValueError(f'ARN {arn} is invalid')
        service, account_id, region, resource = arn_match.groups()
    else:
        service, region, account_id, resource = arn_match.groups()

    service = SERVICE_TRANSFORMS.get(service) or service

    return service, region, account_id, resource


def is_wildcard_arn(arn_string):
    """
    Given an ARN string, determine if that string refers to a unique resource (a legit ARN), or
    if it refers to a wildcard match on multiple ARNs.  The latter is commonly seen in security policies.

    Args:
        arn_string (str): The AWS ARN string to check for wildcards

    Returns:
        True if the ARN string is a true ARN, else False if it's a wildcard pattern
    """
    # For most cases, do a fairly naive check, looking for wildcards characters in the string.
    # It is probably the case that most legitimate identifiers are not allowed to contain a wildcard character.
    # If need be, we can implement arbitrarily complex logic for different real-world cases.
    if '*' in arn_string:
        return True

    # Some legitimate ARNs we see in the wild are not resolvable to single resources, acting like wildcards
    # without a '*'. One particular example is 'arn:aws:apigateway:us-east-1::/restapis' seen in billing data; there's
    # no way to tie this to a single resource without knowing which rest-api it's talking about.
    if 'apigateway' in arn_string and arn_string.endswith('::/restapis'):
        return True

    return False
