from collections.abc import Iterable, Mapping
from typing import Any
from urllib.parse import ParseResult, SplitResult

from requests.auth import AuthBase
from requests.models import Response
from requests.structures import CaseInsensitiveDict

from .lib.url import URL
from .objects import Calendar, DAVObject, Principal

_Element = Any  # actually lxml.etree._Element

class DAVResponse:
    reason: str
    tree: _Element | None
    status: int
    headers: CaseInsensitiveDict[str]
    objects: dict[str, dict[str, str]]  # only defined after call to find_objects_and_props()
    def __init__(self, response: Response) -> None: ...
    @property
    def raw(self) -> str: ...
    def validate_status(self, status: str) -> None: ...
    def find_objects_and_props(self) -> None: ...
    def expand_simple_props(
        self, props: Iterable[Any] = ..., multi_value_props: Iterable[Any] = ..., xpath: str | None = ...
    ) -> dict[str, dict[str, str]]: ...

class DAVClient:
    proxy: str | None
    url: URL
    headers: dict[str, str]
    username: str | None
    password: str | None
    auth: AuthBase | None
    ssl_verify_cert: bool | str
    ssl_cert: str | tuple[str, str] | None
    def __init__(
        self,
        url: str,
        proxy: str | None = ...,
        username: str | None = ...,
        password: str | None = ...,
        auth: AuthBase | None = ...,
        ssl_verify_cert: bool | str = ...,
        ssl_cert: str | tuple[str, str] | None = ...,
    ) -> None: ...
    def principal(self, *, url: str | ParseResult | SplitResult | URL | None = ...) -> Principal: ...
    def calendar(
        self,
        url: str | ParseResult | SplitResult | URL | None = ...,
        parent: DAVObject | None = ...,
        name: str | None = ...,
        id: str | None = ...,
        props: Mapping[Any, Any] = ...,
        **extra: Any,
    ) -> Calendar: ...
    def check_dav_support(self) -> str | None: ...
    def check_cdav_support(self) -> bool: ...
    def check_scheduling_support(self) -> bool: ...
    def propfind(self, url: str | None = ..., props: str = ..., depth: int = ...) -> DAVResponse: ...
    def proppatch(self, url: str, body: str, dummy: None = ...) -> DAVResponse: ...
    def report(self, url: str, query: str = ..., depth: int = ...) -> DAVResponse: ...
    def mkcol(self, url: str, body: str, dummy: None = ...) -> DAVResponse: ...
    def mkcalendar(self, url: str, body: str = ..., dummy: None = ...) -> DAVResponse: ...
    def put(self, url: str, body: str, headers: Mapping[str, str] = ...) -> DAVResponse: ...
    def post(self, url: str, body: str, headers: Mapping[str, str] = ...) -> DAVResponse: ...
    def delete(self, url: str) -> DAVResponse: ...
    def options(self, url: str) -> DAVResponse: ...
    def request(self, url: str, method: str = ..., body: str = ..., headers: Mapping[str, str] = ...) -> DAVResponse: ...
