from collections.abc import Callable
from enum import Flag, IntEnum
from fractions import Fraction
from pathlib import Path
from types import TracebackType
from typing import Any, ClassVar, Literal, Self, TypedDict, cast, overload

from av.codec.hwaccel import HWAccel
from av.format import ContainerFormat

from .input import InputContainer
from .output import OutputContainer
from .streams import StreamContainer

Real = int | float | Fraction

class Flags(Flag):
    gen_pts = cast(ClassVar[Flags], ...)
    ign_idx = cast(ClassVar[Flags], ...)
    non_block = cast(ClassVar[Flags], ...)
    ign_dts = cast(ClassVar[Flags], ...)
    no_fillin = cast(ClassVar[Flags], ...)
    no_parse = cast(ClassVar[Flags], ...)
    no_buffer = cast(ClassVar[Flags], ...)
    custom_io = cast(ClassVar[Flags], ...)
    discard_corrupt = cast(ClassVar[Flags], ...)
    flush_packets = cast(ClassVar[Flags], ...)
    bitexact = cast(ClassVar[Flags], ...)
    sort_dts = cast(ClassVar[Flags], ...)
    fast_seek = cast(ClassVar[Flags], ...)
    shortest = cast(ClassVar[Flags], ...)
    auto_bsf = cast(ClassVar[Flags], ...)

class AudioCodec(IntEnum):
    none = cast(int, ...)
    pcm_alaw = cast(int, ...)
    pcm_bluray = cast(int, ...)
    pcm_dvd = cast(int, ...)
    pcm_f16le = cast(int, ...)
    pcm_f24le = cast(int, ...)
    pcm_f32be = cast(int, ...)
    pcm_f32le = cast(int, ...)
    pcm_f64be = cast(int, ...)
    pcm_f64le = cast(int, ...)
    pcm_lxf = cast(int, ...)
    pcm_mulaw = cast(int, ...)
    pcm_s16be = cast(int, ...)
    pcm_s16be_planar = cast(int, ...)
    pcm_s16le = cast(int, ...)
    pcm_s16le_planar = cast(int, ...)
    pcm_s24be = cast(int, ...)
    pcm_s24daud = cast(int, ...)
    pcm_s24le = cast(int, ...)
    pcm_s24le_planar = cast(int, ...)
    pcm_s32be = cast(int, ...)
    pcm_s32le = cast(int, ...)
    pcm_s32le_planar = cast(int, ...)
    pcm_s64be = cast(int, ...)
    pcm_s64le = cast(int, ...)
    pcm_s8 = cast(int, ...)
    pcm_s8_planar = cast(int, ...)
    pcm_u16be = cast(int, ...)
    pcm_u16le = cast(int, ...)
    pcm_u24be = cast(int, ...)
    pcm_u24le = cast(int, ...)
    pcm_u32be = cast(int, ...)
    pcm_u32le = cast(int, ...)
    pcm_u8 = cast(int, ...)
    pcm_vidc = cast(int, ...)

class Chapter(TypedDict):
    id: int
    start: int
    end: int
    time_base: Fraction | None
    metadata: dict[str, str]

class Container:
    name: str
    metadata_encoding: str
    metadata_errors: str
    file: Any
    buffer_size: int
    io_open: Any
    open_files: Any
    format: ContainerFormat
    options: dict[str, str]
    container_options: dict[str, str]
    stream_options: list[dict[str, str]]
    streams: StreamContainer
    metadata: dict[str, str]
    open_timeout: Real | None
    read_timeout: Real | None
    flags: int
    video_codec_id: int
    def __enter__(self) -> Self: ...
    def __exit__(
        self,
        exc_type: type[BaseException] | None,
        exc_val: BaseException | None,
        exc_tb: TracebackType | None,
    ) -> None: ...
    @property
    def input_was_opened(self) -> bool: ...
    def close(self) -> None: ...
    def chapters(self) -> list[Chapter]: ...
    def set_chapters(self, chapters: list[Chapter]) -> None: ...

@overload
def open(
    file: Any,
    mode: Literal["r"],
    format: str | None = None,
    options: dict[str, str] | None = None,
    container_options: dict[str, str] | None = None,
    stream_options: list[str] | None = None,
    metadata_encoding: str = "utf-8",
    metadata_errors: str = "strict",
    buffer_size: int = 32768,
    timeout: Real | None | tuple[Real | None, Real | None] = None,
    io_open: Callable[..., Any] | None = None,
    hwaccel: HWAccel | None = None,
) -> InputContainer: ...
@overload
def open(
    file: str | Path,
    mode: Literal["r"] | None = None,
    format: str | None = None,
    options: dict[str, str] | None = None,
    container_options: dict[str, str] | None = None,
    stream_options: list[str] | None = None,
    metadata_encoding: str = "utf-8",
    metadata_errors: str = "strict",
    buffer_size: int = 32768,
    timeout: Real | None | tuple[Real | None, Real | None] = None,
    io_open: Callable[..., Any] | None = None,
    hwaccel: HWAccel | None = None,
) -> InputContainer: ...
@overload
def open(
    file: Any,
    mode: Literal["w"],
    format: str | None = None,
    options: dict[str, str] | None = None,
    container_options: dict[str, str] | None = None,
    stream_options: list[str] | None = None,
    metadata_encoding: str = "utf-8",
    metadata_errors: str = "strict",
    buffer_size: int = 32768,
    timeout: Real | None | tuple[Real | None, Real | None] = None,
    io_open: Callable[..., Any] | None = None,
    hwaccel: HWAccel | None = None,
) -> OutputContainer: ...
@overload
def open(
    file: Any,
    mode: Literal["r", "w"] | None = None,
    format: str | None = None,
    options: dict[str, str] | None = None,
    container_options: dict[str, str] | None = None,
    stream_options: list[str] | None = None,
    metadata_encoding: str = "utf-8",
    metadata_errors: str = "strict",
    buffer_size: int = 32768,
    timeout: Real | None | tuple[Real | None, Real | None] = None,
    io_open: Callable[..., Any] | None = None,
    hwaccel: HWAccel | None = None,
) -> InputContainer | OutputContainer: ...
