from collections.abc import Callable, Generator, Sequence
from enum import Enum
from typing import ParamSpec, Protocol, TypeVar

from pydantic import BaseModel

import cybee_sdk.api as cybee_api
from cybee_sdk.api.models.agent_info import AgentInfo

T_co = TypeVar("T_co", bound=BaseModel, covariant=True)
P = ParamSpec("P")


class HasItems(Protocol[T_co]):
    @property
    def items(self) -> Sequence[T_co]: ...


def sizeof_fmt(num, suffix="B"):
    for unit in ("", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"):
        if abs(num) < 1024.0:
            return f"{num:3.1f}{unit}{suffix}"
        num /= 1024.0
    return f"{num:.1f}Yi{suffix}"


def paginator(query_function: Callable[P, HasItems[T_co]], /, *args: P.args, **kwargs: P.kwargs) -> Generator[T_co]:
    page_number = 0

    while True:
        kwargs["page"] = page_number
        resp = query_function(*args, **kwargs)
        if not resp.items:
            break
        yield from resp.items

        page_number += 1

    return


def list_agents(api_configuration: cybee_api.Configuration, /, *args, **kwargs) -> Generator[AgentInfo]:
    with cybee_api.ApiClient(api_configuration) as api_client:
        agent_api = cybee_api.AgentsApi(api_client)
        yield from paginator(agent_api.list_agent_agent_get, *args, **kwargs)


class PlanKind(Enum):
    BACKUP = "backup"
    RESTORE = "restore"


class PlanMode(Enum):
    FILE = "file"
    IMAGE = "image"
