"""Collection releated utils."""

from typing import Any
from typing import Callable
from typing import Dict
from typing import List

from .errors import RecursionLimitExceededError
from .errors import UnexpectedActivityTypeError


def parse_collection(  # noqa: C901
    payload: Dict[str, Any] | None = None,
    url: str | None = None,
    level: int = 0,
    fetcher: Callable[[str], Dict[str, Any]] | None = 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 isinstance(payload["first"], str):
                out.extend(
                    parse_collection(
                        url=payload["first"], level=level + 1, fetcher=fetcher
                    )
                )
            else:
                if "orderedItems" in payload["first"]:
                    out.extend(payload["first"]["orderedItems"])
                if "items" in payload["first"]:
                    out.extend(payload["first"]["items"])
                if n := payload["first"].get("next"):
                    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"])
            if (n := payload.get("next")) is None:
                break
            payload = fetcher(n)
        else:
            raise UnexpectedActivityTypeError(
                "unexpected activity type {}".format(payload["type"])
            )

    return out
