import re
from _typeshed import StrOrBytesPath, SupportsLenAndGetItem, Unused
from collections import defaultdict
from collections.abc import Collection, Iterable
from io import BytesIO
from typing import Literal
from typing_extensions import Self, TypeAlias

FREE_NS: str
types: dict[str, MIMEtype]
exts: Unused | None  # This appears to be unused.
globs: GlobDB | None
literals: Unused | None  # This appears to be unused.
magic: MagicDB | None
PY3: Literal[True]

_MimeTypeWeightPair: TypeAlias = tuple[MIMEtype, int]

def lookup(media: str, subtype: str | None = None) -> MIMEtype: ...

class MIMEtype:
    def __new__(cls, media: str, subtype: str | None = None) -> Self: ...
    def get_comment(self) -> str: ...
    def canonical(self) -> Self: ...
    def inherits_from(self) -> set[MIMEtype]: ...
    def __hash__(self) -> int: ...

class UnknownMagicRuleFormat(ValueError): ...
class DiscardMagicRules(Exception): ...

class MagicRule:
    also: MagicRule | MagicMatchAny | None
    start: int
    value: bytes
    mask: bytes | None
    word: int
    range: int
    def __init__(self, start: int, value: bytes, mask: bytes, word: int, range: int) -> None: ...
    rule_ending_re: re.Pattern[str]
    @classmethod
    def from_file(cls, f: BytesIO) -> tuple[int, MagicRule]: ...
    def maxlen(self) -> int: ...
    def match(self, buffer: SupportsLenAndGetItem[bytes]) -> bool: ...
    def match0(self, buffer: SupportsLenAndGetItem[bytes]) -> bool: ...

class MagicMatchAny:
    rules: Collection[MagicRule]
    def __init__(self, rules: Iterable[MagicRule]) -> None: ...
    def match(self, buffer: SupportsLenAndGetItem[bytes]) -> bool: ...
    def maxlen(self) -> int: ...
    @classmethod
    def from_file(cls, f: BytesIO) -> MagicMatchAny | MagicRule | None: ...
    @classmethod
    def from_rule_tree(cls, tree: list[MagicRule]) -> MagicMatchAny | MagicRule | None: ...

class MagicDB:
    bytype: defaultdict[MIMEtype, list[tuple[int, MagicRule]]]
    def __init__(self) -> None: ...
    def merge_file(self, fname: StrOrBytesPath) -> None: ...
    alltypes: list[tuple[int, MIMEtype, MagicRule]]
    maxlen: int
    def finalise(self) -> None: ...
    def match_data(
        self, data: bytes, max_pri: int = 100, min_pri: int = 0, possible: Iterable[MIMEtype] | None = None
    ) -> MIMEtype: ...
    def match(
        self, path: StrOrBytesPath, max_pri: int = 100, min_pri: int = 0, possible: Iterable[MIMEtype] | None = None
    ) -> MIMEtype: ...

class GlobDB:
    allglobs: defaultdict[MIMEtype, list[tuple[int, str, str]]]
    def __init__(self) -> None: ...
    def merge_file(self, path: StrOrBytesPath) -> None: ...
    exts: defaultdict[str, list[MIMEtype | int]]  # Actually list[MIMEtype, int], but that's not valid.
    cased_exts: defaultdict[str, list[MIMEtype | int]]  # Actually list[MIMEtype, int], but that's not valid.
    globs: list[tuple[re.Pattern[str], MIMEtype, int]]
    literals: dict[str, _MimeTypeWeightPair]
    cased_literals: dict[str, _MimeTypeWeightPair]
    def finalise(self) -> None: ...
    def first_match(self, path: StrOrBytesPath) -> _MimeTypeWeightPair | None: ...
    def all_matches(self, path: StrOrBytesPath) -> list[_MimeTypeWeightPair]: ...

text: MIMEtype
octet_stream: MIMEtype
inode_block: MIMEtype
inode_char: MIMEtype
inode_dir: MIMEtype
inode_fifo: MIMEtype
inode_socket: MIMEtype
inode_symlink: MIMEtype
inode_door: MIMEtype
app_exe: MIMEtype

def update_cache() -> None: ...
def get_type_by_name(path: StrOrBytesPath) -> _MimeTypeWeightPair | None: ...
def get_type_by_contents(path: StrOrBytesPath, max_pri: int = 100, min_pri: int = 0) -> MIMEtype: ...
def get_type_by_data(data: bytes, max_pri: int = 100, min_pri: int = 0) -> MIMEtype: ...
def get_type(path: StrOrBytesPath, follow: bool = True, name_pri: int = 100) -> MIMEtype: ...
def get_type2(path: StrOrBytesPath, follow: bool = True) -> MIMEtype: ...
def is_text_file(path: StrOrBytesPath) -> bool: ...
def get_extensions(mimetype: MIMEtype) -> set[str]: ...
def install_mime_info(application: str, package_file: StrOrBytesPath) -> None: ...
