import typing
from typing import Dict, List, Iterable, Union, Optional, BinaryIO, Iterator, Generic
from os import PathLike

try:
    from typing import Literal
except ImportError:
    from typing_extensions import Literal  # type: ignore

__version__: str
__author__: str

AVX2_SUPPORTED: bool

FORMAT = Literal["jaspar", "jaspar16", "uniprobe", "transfac"]

class EncodedSequence:
    def __init__(self, sequence: str, *, protein: bool = False) -> None: ...
    def __str__(self) -> str: ...
    def __len__(self) -> int: ...
    def __copy__(self) -> EncodedSequence: ...
    def __buffer__(self, flags: int) -> memoryview: ...
    @property
    def protein(self) -> bool: ...
    def copy(self) -> EncodedSequence: ...
    def stripe(self) -> StripedSequence: ...

class StripedSequence:
    def __copy__(self) -> StripedSequence: ...
    def __buffer__(self, flags: int) -> memoryview: ...
    @property
    def protein(self) -> bool: ...
    def copy(self) -> StripedSequence: ...

class CountMatrix:
    def __init__(
        self, values: Dict[str, Iterable[int]], *, protein: bool = False
    ) -> None: ...
    def __eq__(self, other: object) -> bool: ...
    def __len__(self) -> int: ...
    def __getitem__(self, index: int) -> List[int]: ...
    @property
    def protein(self) -> bool: ...
    def normalize(
        self, pseudocount: Union[None, float, Dict[str, float]] = None
    ) -> WeightMatrix: ...

class WeightMatrix:
    def __eq__(self, other: object) -> bool: ...
    def __len__(self) -> int: ...
    def __getitem__(self, index: int) -> List[int]: ...
    @property
    def protein(self) -> bool: ...
    def log_odds(
        self, background: Union[None, Dict[str, float]] = None, base: float = 2.0
    ) -> ScoringMatrix: ...

class ScoringMatrix:
    def __init__(
        self,
        values: Dict[str, Iterable[float]],
        background: Optional[Dict[str, float]] = None,
        *,
        protein: bool = False,
    ) -> None: ...
    def __len__(self) -> int: ...
    def __eq__(self, other: object) -> bool: ...
    def __buffer__(self, flags: int) -> memoryview: ...
    @property
    def protein(self) -> bool: ...
    def calculate(self, sequence: StripedSequence) -> StripedScores: ...
    def pvalue(self, score: float) -> float: ...
    def score(self, pvalue: float) -> float: ...
    def reverse_complement(self) -> ScoringMatrix: ...

class StripedScores:
    def __len__(self) -> int: ...
    def __getitem__(self, index: int) -> float: ...
    def __buffer__(self, flags: int) -> memoryview: ...
    def threshold(self, threshold: float) -> List[int]: ...
    def max(self) -> Optional[float]: ...
    def argmax(self) -> Optional[int]: ...

class Motif:
    @property
    def counts(self) -> Optional[CountMatrix]: ...
    @property
    def pwm(self) -> WeightMatrix: ...
    @property
    def pssm(self) -> ScoringMatrix: ...
    @property
    def name(self) -> Optional[str]: ...
    @property
    def protein(self) -> bool: ...

class TransfacMotif(Motif):
    @property
    def counts(self) -> CountMatrix: ...

class JasparMotif(Motif):
    @property
    def counts(self) -> CountMatrix: ...
    @property
    def name(self) -> str: ...
    @property
    def description(self) -> Optional[str]: ...

class UniprobeMotif(Motif):
    @property
    def counts(self) -> None: ...

class Scanner(Iterator[Hit]):
    def __init__(
        self,
        pssm: ScoringMatrix,
        sequence: StripedSequence,
        threshold: float = 0.0,
        block_size: int = 256,
    ) -> None: ...
    def __iter__(self) -> Scanner: ...
    def __next__(self) -> Hit: ...

class Hit:
    @property
    def position(self) -> int: ...
    @property
    def score(self) -> float: ...

M = typing.TypeVar("M", bound=Motif)

class Loader(Generic[M], Iterator[M]):
    def __init__(
        self,
        file: Union[BinaryIO, PathLike[str]],
        format: Literal["jaspar16"],
        *,
        protein: bool = False,
    ) -> None: ...
    def __iter__(self) -> Loader[M]: ...
    def __next__(self) -> M: ...

def create(
    sequences: Iterable[str], *, protein: bool = False, name: Optional[str] = None
) -> Motif: ...
def stripe(sequence: str, *, protein: bool = False) -> StripedSequence: ...
def scan(
    pssm: ScoringMatrix,
    sequence: StripedSequence,
    *,
    threshold: float = 0.0,
    block_size: int = 256,
) -> Scanner: ...
@typing.overload
def load(
    file: Union[BinaryIO, PathLike[str]],
    format: Literal["jaspar"],
    *,
    protein: bool = False,
) -> Loader[JasparMotif]: ...
@typing.overload
def load(
    file: Union[BinaryIO, PathLike[str]],
    format: Literal["jaspar16"],
    *,
    protein: bool = False,
) -> Loader[JasparMotif]: ...
@typing.overload
def load(
    file: Union[BinaryIO, PathLike[str]],
    format: Literal["uniprobe"],
    *,
    protein: bool = False,
) -> Loader[UniprobeMotif]: ...
@typing.overload
def load(
    file: Union[BinaryIO, PathLike[str]],
    format: Literal["transfac"],
    *,
    protein: bool = False,
) -> Loader[TransfacMotif]: ...
@typing.overload
def load(
    file: Union[BinaryIO, PathLike[str]],
    format: FORMAT = "jaspar",
    *,
    protein: bool = False,
) -> Loader[Motif]: ...
