"""ARN parsing utilities."""

import re
from typing import NamedTuple

REGEX_RESOURCE_TYPE = re.compile(r"^[a-zA-Z0-9-]+$")


class ResourceNotFound(Exception):
    def __init__(self, service, resource):
        super().__init__(
            f"Cannot determine resource format for service {service}: {resource}"
        )


class ARN(NamedTuple):
    partition: str
    service: str
    region: str
    account: str
    resource_type: str | None
    resource_id: str
    resource_name: str


class Resource(NamedTuple):
    resource_type: str | None
    resource_id: str
    resource_name: str


def find_resource(service, resource):
    separators = resource.count("/") + resource.count(":")
    segments = [s for segment in resource.split("/") for s in segment.split(":")]
    prefix = segments[0]
    suffix = resource[len(prefix) + 1 :]

    if service == "apigateway":
        if separators == 2:
            return Resource(segments[1], segments[2], segments[2])
        else:
            raise ResourceNotFound(service, resource)
    elif service == "autoscaling":
        if segments[0] == "autoScalingGroup" and segments[2] == "autoScalingGroupName":
            return Resource(segments[0], segments[1], segments[3])
        else:
            raise ResourceNotFound(service, resource)
    elif service == "cloudformation":
        if separators == 2:
            return Resource(segments[0], segments[2], segments[1])
        else:
            raise ResourceNotFound(service, resource)
    elif service == "cloudwatch":
        if prefix == "alarm":
            return Resource(prefix, suffix, suffix)
        else:
            raise ResourceNotFound(service, resource)
    elif service == "elasticloadbalancing":
        if prefix == "loadbalancer":
            if separators == 3:
                return Resource(
                    f"{segments[0]}/{segments[1]}", segments[3], segments[2]
                )
            elif separators == 1:
                return Resource(segments[0], segments[1], segments[1])
            else:
                raise ResourceNotFound(service, resource)
        elif prefix == "targetgroup":
            if separators == 2:
                return Resource(prefix, segments[2], segments[1])
            else:
                raise ResourceNotFound(service, resource)
        else:
            raise ResourceNotFound(service, resource)
    elif service == "logs":
        if prefix == "log-group":
            return Resource(prefix, suffix, suffix)
        else:
            raise ResourceNotFound(service, resource)
    elif service == "secretsmanager":
        if prefix == "secret":
            return Resource(prefix, suffix, suffix)
        else:
            raise ResourceNotFound(service, resource)
    elif service == "ssm":
        if prefix == "parameter":
            return Resource(prefix, "/" + suffix, "/" + suffix)
        else:
            raise ResourceNotFound(service, resource)
    elif service == "wafv2":
        if prefix == "global":
            return Resource(f"{segments[0]}/{segments[1]}", segments[2], segments[2])
        elif prefix == "regional":
            return Resource(f"{segments[0]}/{segments[1]}", segments[3], segments[2])
        else:
            raise ResourceNotFound(service, resource)
    elif separators == 1:
        return Resource(segments[0], segments[1], segments[1])
    elif separators == 0:
        return Resource(None, segments[0], segments[0])
    else:
        raise ResourceNotFound(service, resource)


def arnparse(arn):
    """Parse an ARN string into components."""
    parts = arn.split(":", 5)
    if len(parts) != 6:
        raise ValueError(f"Invalid ARN format: {arn}")

    if parts[0] != "arn":
        raise ValueError(f"ARN must start with 'arn': {arn}")

    _, partition, service, region, account, resource = parts

    # Global services - no region, no account
    if service in {"s3", "route53"}:
        if region or account:
            raise ValueError(
                f"Service {service} must have empty region and account: {arn}"
            )

    # Global services - no region, has account
    if service in {"cloudfront", "iam"}:
        if region:
            raise ValueError(f"Service {service} must have empty region: {arn}")
        if not account:
            raise ValueError(f"Service {service} must have account: {arn}")

    # Regional services - has region, no account
    if service in {"apigateway"}:
        if not region:
            raise ValueError(f"Service {service} must have region: {arn}")
        if account:
            raise ValueError(f"Service {service} must have empty account: {arn}")

    resource = find_resource(service, resource)

    return ARN(
        partition=partition,
        service=service,
        region=region,
        account=account,
        resource_type=resource.resource_type,
        resource_id=resource.resource_id,
        resource_name=resource.resource_name,
    )
