import sys
from _typeshed import Incomplete
from collections.abc import Callable, MutableMapping
from fractions import Fraction, _ComparableNum
from numbers import Rational
from types import TracebackType
from typing import ClassVar, overload
from typing_extensions import Final, Literal, SupportsIndex, TypeAlias

from ._imaging import _PixelAccessor
from .ImageFile import ImageFile

_OpenInfo: TypeAlias = tuple[Literal[b"II", b"MM"], int, tuple[int, ...], int, tuple[int, ...], tuple[int, ...]]

# These are meant to be overridable
READ_LIBTIFF: bool
WRITE_LIBTIFF: bool
IFD_LEGACY_API: bool
STRIP_SIZE: int

II: Final = b"II"
MM: Final = b"MM"
IMAGEWIDTH: Final = 256
IMAGELENGTH: Final = 257
BITSPERSAMPLE: Final = 258
COMPRESSION: Final = 259
PHOTOMETRIC_INTERPRETATION: Final = 262
FILLORDER: Final = 266
IMAGEDESCRIPTION: Final = 270
STRIPOFFSETS: Final = 273
SAMPLESPERPIXEL: Final = 277
ROWSPERSTRIP: Final = 278
STRIPBYTECOUNTS: Final = 279
X_RESOLUTION: Final = 282
Y_RESOLUTION: Final = 283
PLANAR_CONFIGURATION: Final = 284
RESOLUTION_UNIT: Final = 296
TRANSFERFUNCTION: Final = 301
SOFTWARE: Final = 305
DATE_TIME: Final = 306
ARTIST: Final = 315
PREDICTOR: Final = 317
COLORMAP: Final = 320
TILEWIDTH: Final = 322
TILELENGTH: Final = 323
TILEOFFSETS: Final = 324
TILEBYTECOUNTS: Final = 325
SUBIFD: Final = 330
EXTRASAMPLES: Final = 338
SAMPLEFORMAT: Final = 339
JPEGTABLES: Final = 347
YCBCRSUBSAMPLING: Final = 530
REFERENCEBLACKWHITE: Final = 532
COPYRIGHT: Final = 33432
IPTC_NAA_CHUNK: Final = 33723
PHOTOSHOP_CHUNK: Final = 34377
ICCPROFILE: Final = 34675
EXIFIFD: Final = 34665
XMP: Final = 700
JPEGQUALITY: Final = 65537
IMAGEJ_META_DATA_BYTE_COUNTS: Final = 50838
IMAGEJ_META_DATA: Final = 50839
COMPRESSION_INFO: Final[dict[int, str]]
COMPRESSION_INFO_REV: Final[dict[str, int]]
OPEN_INFO: Final[dict[_OpenInfo, tuple[str, str]]]
MAX_SAMPLESPERPIXEL: Final = 6
PREFIXES: Final[list[bytes]]

class IFDRational(Rational):
    def __init__(self, value, denominator: int = 1) -> None: ...
    @property
    def numerator(a): ...
    @property
    def denominator(a): ...
    def limit_rational(self, max_denominator): ...
    def __hash__(self) -> int: ...
    def __eq__(self, other): ...
    # The following methods are aliased from fractions.Fraction:
    @overload
    def __add__(a, b: int | Fraction) -> Fraction: ...
    @overload
    def __add__(a, b: float) -> float: ...
    @overload
    def __add__(a, b: complex) -> complex: ...
    @overload
    def __radd__(b, a: int | Fraction) -> Fraction: ...
    @overload
    def __radd__(b, a: float) -> float: ...
    @overload
    def __radd__(b, a: complex) -> complex: ...
    @overload
    def __sub__(a, b: int | Fraction) -> Fraction: ...
    @overload
    def __sub__(a, b: float) -> float: ...
    @overload
    def __sub__(a, b: complex) -> complex: ...
    @overload
    def __rsub__(b, a: int | Fraction) -> Fraction: ...
    @overload
    def __rsub__(b, a: float) -> float: ...
    @overload
    def __rsub__(b, a: complex) -> complex: ...
    @overload
    def __mul__(a, b: int | Fraction) -> Fraction: ...
    @overload
    def __mul__(a, b: float) -> float: ...
    @overload
    def __mul__(a, b: complex) -> complex: ...
    @overload
    def __rmul__(b, a: int | Fraction) -> Fraction: ...
    @overload
    def __rmul__(b, a: float) -> float: ...
    @overload
    def __rmul__(b, a: complex) -> complex: ...
    @overload
    def __truediv__(a, b: int | Fraction) -> Fraction: ...
    @overload
    def __truediv__(a, b: float) -> float: ...
    @overload
    def __truediv__(a, b: complex) -> complex: ...
    @overload
    def __rtruediv__(b, a: int | Fraction) -> Fraction: ...
    @overload
    def __rtruediv__(b, a: float) -> float: ...
    @overload
    def __rtruediv__(b, a: complex) -> complex: ...
    @overload
    def __floordiv__(a, b: int | Fraction) -> int: ...
    @overload
    def __floordiv__(a, b: float) -> float: ...
    @overload
    def __rfloordiv__(b, a: int | Fraction) -> int: ...
    @overload
    def __rfloordiv__(b, a: float) -> float: ...
    @overload
    def __mod__(a, b: int | Fraction) -> Fraction: ...
    @overload
    def __mod__(a, b: float) -> float: ...
    @overload
    def __rmod__(b, a: int | Fraction) -> Fraction: ...
    @overload
    def __rmod__(b, a: float) -> float: ...
    @overload
    def __pow__(a, b: int) -> Fraction: ...
    @overload
    def __pow__(a, b: float | Fraction) -> float: ...
    @overload
    def __pow__(a, b: complex) -> complex: ...
    @overload
    def __rpow__(b, a: float | Fraction) -> float: ...
    @overload
    def __rpow__(b, a: complex) -> complex: ...
    def __pos__(a) -> Fraction: ...
    def __neg__(a) -> Fraction: ...
    def __abs__(a) -> Fraction: ...
    def __trunc__(a) -> int: ...
    def __lt__(a, b: _ComparableNum) -> bool: ...
    def __gt__(a, b: _ComparableNum) -> bool: ...
    def __le__(a, b: _ComparableNum) -> bool: ...
    def __ge__(a, b: _ComparableNum) -> bool: ...
    def __bool__(a) -> bool: ...
    def __ceil__(a) -> int: ...
    def __floor__(a) -> int: ...
    @overload
    def __round__(self, ndigits: None = None) -> int: ...
    @overload
    def __round__(self, ndigits: int) -> Fraction: ...
    if sys.version_info >= (3, 11):
        def __int__(a, _index: Callable[[SupportsIndex], int] = ...) -> int: ...

class ImageFileDirectory_v2(MutableMapping[int, Incomplete]):
    group: int | None
    tagtype: dict[int, int]
    def __init__(
        self, ifh: bytes = b"II*\x00\x00\x00\x00\x00", prefix: bytes | None = None, group: int | None = None
    ) -> None: ...
    @property
    def prefix(self) -> bytes: ...
    @property
    def offset(self) -> int | None: ...
    @property
    def legacy_api(self) -> bool: ...
    def reset(self) -> None: ...
    def named(self): ...
    def __len__(self) -> int: ...
    def __getitem__(self, tag): ...
    def __contains__(self, tag): ...
    def __setitem__(self, tag, value) -> None: ...
    def __delitem__(self, tag) -> None: ...
    def __iter__(self): ...
    def load_byte(self, data, legacy_api: bool = True): ...
    def write_byte(self, data): ...
    def load_string(self, data, legacy_api: bool = True): ...
    def write_string(self, value: int | str | bytes) -> bytes: ...
    def load_rational(self, data, legacy_api: bool = True): ...
    def write_rational(self, *values): ...
    def load_undefined(self, data, legacy_api: bool = True): ...
    def write_undefined(self, value): ...
    def load_signed_rational(self, data, legacy_api: bool = True): ...
    def write_signed_rational(self, *values): ...
    def load(self, fp) -> None: ...
    def tobytes(self, offset: int = 0): ...
    def save(self, fp): ...
    load_double: Incomplete
    load_float: Incomplete
    load_long: Incomplete
    load_long8: Incomplete
    load_short: Incomplete
    load_signed_byte: Incomplete
    load_signed_long: Incomplete
    load_signed_short: Incomplete
    write_double: Incomplete
    write_float: Incomplete
    write_long: Incomplete
    write_long8: Incomplete
    write_short: Incomplete
    write_signed_byte: Incomplete
    write_signed_long: Incomplete
    write_signed_short: Incomplete

class ImageFileDirectory_v1(ImageFileDirectory_v2):
    def __init__(self, *args, **kwargs) -> None: ...
    @property
    def tags(self): ...
    @property
    def tagdata(self): ...
    tagtype: dict[int, int]
    @classmethod
    def from_v2(cls, original): ...
    def to_v2(self): ...
    def __contains__(self, tag): ...
    def __len__(self) -> int: ...
    def __iter__(self): ...
    def __setitem__(self, tag, value) -> None: ...
    def __getitem__(self, tag): ...

ImageFileDirectory = ImageFileDirectory_v1

class TiffImageFile(ImageFile):
    format: ClassVar[Literal["TIFF", "MIC"]]
    format_description: ClassVar[str]
    tag_v2: Incomplete
    tag: Incomplete
    def __init__(self, fp: Incomplete | None = None, filename: Incomplete | None = None) -> None: ...
    @property
    def n_frames(self): ...
    im: Incomplete
    def seek(self, frame) -> None: ...
    def tell(self): ...
    def getxmp(self): ...
    def get_photoshop_blocks(self): ...
    def load(self) -> _PixelAccessor: ...
    def load_end(self) -> None: ...

SAVE_INFO: Incomplete

class AppendingTiffWriter:
    fieldSizes: Incomplete
    Tags: Incomplete
    f: Incomplete
    close_fp: bool
    name: Incomplete
    beginning: Incomplete
    def __init__(self, fn, new: bool = False) -> None: ...
    whereToWriteNewIFDOffset: Incomplete
    offsetOfNewPage: int
    IIMM: Incomplete
    isFirst: bool
    def setup(self) -> None: ...
    def finalize(self) -> None: ...
    def newFrame(self) -> None: ...
    def __enter__(self): ...
    def __exit__(
        self, exc_type: type[BaseException] | None, exc_value: BaseException | None, traceback: TracebackType | None
    ) -> Literal[False]: ...
    def tell(self): ...
    def seek(self, offset, whence=0): ...
    def goToEnd(self) -> None: ...
    endian: Incomplete
    longFmt: Incomplete
    shortFmt: Incomplete
    tagFormat: Incomplete
    def setEndian(self, endian) -> None: ...
    def skipIFDs(self) -> None: ...
    def write(self, data): ...
    def readShort(self): ...
    def readLong(self): ...
    def rewriteLastShortToLong(self, value) -> None: ...
    def rewriteLastShort(self, value) -> None: ...
    def rewriteLastLong(self, value) -> None: ...
    def writeShort(self, value) -> None: ...
    def writeLong(self, value) -> None: ...
    def close(self) -> None: ...
    def fixIFD(self) -> None: ...
    def fixOffsets(self, count, isShort: bool = False, isLong: bool = False) -> None: ...
