"""Contains some ActivityPub related utils."""
from typing import Optional
from typing import Callable
from typing import Dict
from typing import List
from typing import Any


from .errors import RecursionLimitExceededError
from .errors import UnexpectedActivityTypeError


def parse_collection(
    payload: Optional[Dict[str, Any]] = None,
    url: Optional[str] = None,
    level: int = 0,
    fetcher: Optional[Callable[[str], Dict[str, Any]]] = None,
) -> List[Any]:
    """Resolve/fetch a `Collection`/`OrderedCollection`."""
    if not fetcher:
        raise Exception("must provide a fetcher")
    if level > 3:
        raise RecursionLimitExceededError("recursion limit exceeded")

    # Go through all the pages
    out: List[Any] = []
    if url:
        payload = fetcher(url)
    if not payload:
        raise ValueError("must at least prove a payload or an URL")

    if payload["type"] in ["Collection", "OrderedCollection"]:
        if "orderedItems" in payload:
            return payload["orderedItems"]
        if "items" in payload:
            return payload["items"]
        if "first" in payload:
            if "orderedItems" in payload["first"]:
                out.extend(payload["first"]["orderedItems"])
            if "items" in payload["first"]:
                out.extend(payload["first"]["items"])
            n = payload["first"].get("next")
            if n:
                out.extend(parse_collection(url=n, level=level + 1, fetcher=fetcher))
        return out

    while payload:
        if payload["type"] in ["CollectionPage", "OrderedCollectionPage"]:
            if "orderedItems" in payload:
                out.extend(payload["orderedItems"])
            if "items" in payload:
                out.extend(payload["items"])
            n = payload.get("next")
            if n is None:
                break
            payload = fetcher(n)
        else:
            raise UnexpectedActivityTypeError(
                "unexpected activity type {}".format(payload["type"])
            )

    return out
