import types
from collections.abc import Callable, Collection, Iterable, Iterator, Mapping
from functools import cached_property
from types import TracebackType
from typing import Any
from typing_extensions import Self, TypeAlias
from urllib.request import Request

from yt_dlp.cache import Cache
from yt_dlp.cookies import YoutubeDLCookieJar
from yt_dlp.networking import RequestDirector, RequestHandler, Response
from yt_dlp.utils import Namespace

from . import _Params
from .extractor.common import InfoExtractor, _InfoDict
from .postprocessor.common import PostProcessor
from .utils._utils import _ProgressState

_FormatSelector: TypeAlias = Callable[[Mapping[str, Any]], Iterator[Any]]

class YoutubeDL:
    params: _Params
    cache: Cache
    format_selector: _FormatSelector
    archive: set[str]
    def __init__(self, params: _Params | None = None, auto_init: bool = True) -> None: ...
    def warn_if_short_id(self, argv: list[str]) -> None: ...
    def add_info_extractor(self, ie: InfoExtractor) -> None: ...
    def get_info_extractor(self, ie_key: str) -> InfoExtractor: ...
    def add_default_info_extractors(self) -> None: ...
    def add_post_processor(self, pp: PostProcessor, when: str = "post_process") -> None: ...
    def add_post_hook(self, ph: Callable[..., object]) -> None: ...
    def add_close_hook(self, ch: Callable[..., object]) -> None: ...
    def add_progress_hook(self, ph: Callable[..., object]) -> None: ...
    def add_postprocessor_hook(self, ph: Callable[..., object]) -> None: ...
    def to_stdout(self, message: str, skip_eol: bool = False, quiet: bool | None = None) -> None: ...
    def to_screen(self, message: str, skip_eol: bool = False, quiet: bool | None = None, only_once: bool = False) -> None: ...
    def to_stderr(self, message: str, only_once: bool = False) -> None: ...
    def to_console_title(
        self, message: str | None = None, progress_state: _ProgressState | None = None, percent: int | None = None
    ) -> None: ...
    def save_console_title(self) -> None: ...
    def restore_console_title(self) -> None: ...
    def __enter__(self) -> Self: ...
    def save_cookies(self) -> None: ...
    def __exit__(self, *args: object) -> None: ...
    def close(self) -> None: ...
    def trouble(self, message: str | None = None, tb: TracebackType | None = None, is_error: bool = True) -> None: ...
    Styles: Namespace
    def report_warning(self, message: str, only_once: bool = False) -> None: ...
    def deprecation_warning(self, message: str, *, stacklevel: int = 0) -> None: ...
    def deprecated_feature(self, message: str) -> None: ...
    def report_error(self, message: str, tb: types.TracebackType | None = None, is_error: bool = True) -> None: ...
    def write_debug(self, message: str, only_once: bool = False) -> None: ...
    def report_file_already_downloaded(self, file_name: str) -> None: ...
    def report_file_delete(self, file_name: str) -> None: ...
    def raise_no_formats(self, info: str, forced: bool = False, *, msg: str | None = None) -> None: ...
    def get_output_path(self, dir_type: str = "", filename: str | None = None) -> str: ...
    @staticmethod
    def escape_outtmpl(outtmpl: str) -> str: ...
    @classmethod
    def validate_outtmpl(cls, outtmpl: str) -> ValueError | None: ...
    def prepare_outtmpl(self, outtmpl: str, info_dict: _InfoDict, sanitize: bool = False) -> tuple[str, dict[str, Any]]: ...
    def evaluate_outtmpl(self, outtmpl: str, info_dict: _InfoDict, sanitize: bool = False) -> str: ...
    def prepare_filename(
        self, info_dict: _InfoDict, dir_type: str = "", *, outtmpl: str | None = None, warn: bool = False
    ) -> str: ...
    @staticmethod
    def add_extra_info(info_dict: _InfoDict, extra_info: Mapping[str, Any]) -> None: ...
    def extract_info(
        self,
        url: str,
        download: bool = True,
        ie_key: str | None = None,
        extra_info: Any | None = None,
        process: bool = True,
        force_generic_extractor: bool = False,
    ) -> _InfoDict: ...
    def add_default_extra_info(self, ie_result: _InfoDict, ie: InfoExtractor, url: str) -> None: ...
    def process_ie_result(
        self, ie_result: _InfoDict, download: bool = True, extra_info: Mapping[str, Any] | None = None
    ) -> _InfoDict: ...
    def build_format_selector(self, format_spec: str) -> _FormatSelector: ...
    def sort_formats(self, info_dict: _InfoDict) -> None: ...
    def process_video_result(self, info_dict: _InfoDict, download: bool = True) -> _InfoDict: ...
    def process_subtitles(
        self, video_id: str, normal_subtitles: Mapping[str, Any], automatic_captions: Mapping[str, Any]
    ) -> dict[str, Any] | None: ...
    def dl(self, name: str, info: _InfoDict, subtitle: bool = False, test: bool = False) -> bool: ...
    def existing_file(self, filepaths: Iterable[str], *, default_overwrite: bool = True) -> str | None: ...
    def process_info(self, info_dict: _InfoDict) -> None: ...
    def download(self, url_list: Collection[str]) -> None: ...
    def download_with_info_file(self, info_filename: str) -> int: ...
    @staticmethod
    def sanitize_info(info_dict: _InfoDict, remove_private_keys: bool = False) -> _InfoDict | None: ...
    @staticmethod
    def filter_requested_info(info_dict: _InfoDict, actually_filter: bool = True) -> _InfoDict | None: ...
    @staticmethod
    def post_extract(info_dict: _InfoDict) -> None: ...
    def run_pp(self, pp: PostProcessor, infodict: _InfoDict) -> _InfoDict: ...
    def run_all_pps(self, key: str, info: _InfoDict, *, additional_pps: Collection[PostProcessor] | None = None) -> _InfoDict: ...
    def pre_process(
        self, ie_info: _InfoDict, key: str = "pre_process", files_to_move: Mapping[str, Any] | None = None
    ) -> tuple[_InfoDict, list[str] | None]: ...
    def post_process(self, filename: str, info: _InfoDict, files_to_move: Mapping[str, Any] | None = None) -> _InfoDict: ...
    def in_download_archive(self, info_dict: _InfoDict) -> bool: ...
    def record_download_archive(self, info_dict: _InfoDict) -> None: ...
    @staticmethod
    def format_resolution(format: Mapping[str, Any], default: str = "unknown") -> str: ...
    def render_formats_table(self, info_dict: _InfoDict) -> str | None: ...
    def render_thumbnails_table(self, info_dict: _InfoDict) -> str | None: ...
    def render_subtitles_table(self, video_id: str, subtitles: Iterable[Mapping[str, Any]]) -> str | None: ...
    def list_formats(self, info_dict: _InfoDict) -> None: ...
    def list_thumbnails(self, info_dict: _InfoDict) -> None: ...
    def list_subtitles(self, video_id: str, subtitles: Iterable[Mapping[str, Any]], name: str = "subtitles") -> None: ...
    def print_debug_header(self) -> None: ...
    @cached_property
    def proxies(self) -> dict[str, Any]: ...
    @cached_property
    def cookiejar(self) -> YoutubeDLCookieJar: ...
    def urlopen(self, req: Request | str) -> Response: ...
    def build_request_director(
        self, handlers: Collection[RequestHandler], preferences: Collection[Any] | None = None
    ) -> RequestDirector: ...
    def encode(self, s: str) -> bytes: ...
    def get_encoding(self) -> str: ...
