from _typeshed import ConvertibleToInt, Incomplete
from collections.abc import Generator, Iterator
from itertools import product
from typing import Any, Literal, overload

from openpyxl.descriptors import Strict
from openpyxl.descriptors.base import MinMax
from openpyxl.descriptors.serialisable import Serialisable

class CellRange(Serialisable):
    min_col: MinMax[int, Literal[False]]
    min_row: MinMax[int, Literal[False]]
    max_col: MinMax[int, Literal[False]]
    max_row: MinMax[int, Literal[False]]
    title: str | None

    # With `range_string`, min/max parameters go unused.
    # Enforcing `None` to avoid confusion upon which params get used
    # if the user still tries to pass a `ConvertibleToInt`.
    @overload
    def __init__(
        self,
        range_string: str,
        min_col: None = None,
        min_row: None = None,
        max_col: None = None,
        max_row: None = None,
        title: str | None = None,
    ) -> None: ...
    @overload
    def __init__(
        self,
        range_string: None = None,
        *,
        min_col: ConvertibleToInt,
        min_row: ConvertibleToInt,
        max_col: ConvertibleToInt,
        max_row: ConvertibleToInt,
        title: str | None = None,
    ) -> None: ...
    @overload
    def __init__(
        self,
        range_string: None,
        min_col: ConvertibleToInt,
        min_row: ConvertibleToInt,
        max_col: ConvertibleToInt,
        max_row: ConvertibleToInt,
        title: str | None = None,
    ) -> None: ...

    @property
    def bounds(self) -> tuple[int, int, int, int]: ...
    @property
    def coord(self) -> str: ...
    @property
    def rows(self) -> Generator[list[tuple[int, int]]]: ...
    @property
    def cols(self) -> Generator[list[tuple[int, int]]]: ...
    @property
    def cells(self) -> product[tuple[int, int]]: ...
    def __copy__(self): ...
    def shift(self, col_shift: int = 0, row_shift: int = 0) -> None: ...
    def __ne__(self, other: object) -> bool: ...
    def __eq__(self, other: object) -> bool: ...
    def issubset(self, other: CellRange) -> bool: ...
    __le__ = issubset
    def __lt__(self, other: CellRange) -> bool: ...
    def issuperset(self, other: CellRange) -> bool: ...
    __ge__ = issuperset
    def __contains__(self, coord: str) -> bool: ...
    def __gt__(self, other: CellRange) -> bool: ...
    def isdisjoint(self, other: CellRange) -> bool: ...
    def intersection(self, other): ...
    __and__ = intersection
    def union(self, other): ...
    __or__ = union
    # Iterates over class attributes. Value could be anything.
    def __iter__(self) -> Iterator[tuple[str, Any]]: ...
    def expand(self, right: int = 0, down: int = 0, left: int = 0, up: int = 0) -> None: ...
    def shrink(self, right: int = 0, bottom: int = 0, left: int = 0, top: int = 0) -> None: ...
    @property
    def size(self) -> dict[str, int]: ...
    @property
    def top(self) -> list[tuple[int, int]]: ...
    @property
    def bottom(self) -> list[tuple[int, int]]: ...
    @property
    def left(self) -> list[tuple[int, int]]: ...
    @property
    def right(self) -> list[tuple[int, int]]: ...

class MultiCellRange(Strict):
    ranges: Incomplete
    def __init__(self, ranges=...) -> None: ...
    def __contains__(self, coord: str | CellRange) -> bool: ...
    def sorted(self) -> list[CellRange]: ...
    def add(self, coord) -> None: ...
    def __iadd__(self, coord): ...
    def __eq__(self, other: str | MultiCellRange) -> bool: ...  # type: ignore[override]
    def __ne__(self, other: str | MultiCellRange) -> bool: ...  # type: ignore[override]
    def __bool__(self) -> bool: ...
    def remove(self, coord) -> None: ...
    def __iter__(self) -> Iterator[CellRange]: ...
    def __copy__(self): ...
