from __future__ import annotations

import json
from dataclasses import dataclass
from functools import lru_cache
from importlib import resources


@dataclass(frozen=True, slots=True)
class IamActionCatalog:
    services: dict[str, dict[str, bool]]
    action_to_services: dict[str, tuple[str, ...]]

    def has_service(self, prefix: str) -> bool:
        return prefix in self.services

    def has_action(self, prefix: str, action: str) -> bool:
        return action in self.services.get(prefix, {})

    def supports_resource_scope(self, prefix: str, action: str) -> bool | None:
        actions = self.services.get(prefix)
        if not actions or action not in actions:
            return None
        return actions[action]

    def find_services_for_action(self, action: str) -> tuple[str, ...]:
        return self.action_to_services.get(action, ())

    def service_actions(self, prefix: str) -> tuple[str, ...]:
        return tuple(self.services.get(prefix, {}))

    def service_prefixes(self) -> tuple[str, ...]:
        return tuple(self.services)


@lru_cache(maxsize=1)
def load_iam_action_catalog() -> IamActionCatalog:
    package_file = resources.files("aws_guardrails.data").joinpath("iam_actions_min.json")
    raw = json.loads(package_file.read_text(encoding="utf-8"))
    services = {prefix: spec["actions"] for prefix, spec in raw["services"].items()}

    action_to_services: dict[str, list[str]] = {}
    for prefix, actions in services.items():
        for action in actions:
            action_to_services.setdefault(action, []).append(prefix)

    return IamActionCatalog(
        services=services,
        action_to_services={action: tuple(sorted(prefixes)) for action, prefixes in action_to_services.items()},
    )
