# --- Python imports ---------------------------------------------------------

import os
from typing import Sequence, List, Optional, Union, Sequence

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

# --- Alignment classes ------------------------------------------------------

class AlignmentSequences:
    def __init__(self, alignment: Alignment) -> None: ...
    def __len__(self) -> int: ...
    def __getitem__(self, index: int) -> str: ...


class AlignmentResidues:
    def __init__(self, alignment: Alignment) -> None: ...
    def __len__(self) -> int: ...
    def __getitem__(self, index: int) -> str: ...


class Alignment:
    @classmethod
    def load(cls, path: Union[str, bytes, os.PathLike[str]]) -> Alignment: ...
    def __init__(self, names: Sequence[bytes], sequences: Sequence[str]) -> None: ...
    def __repr__(self) -> str: ...
    def __copy__(self) -> Alignment: ...
    @property
    def names(self) -> List[bytes]: ...
    @property
    def sequences(self) -> AlignmentSequences: ...
    @property
    def residues(self) -> AlignmentResidues: ...
    def copy(self) -> Alignment: ...


class TrimmedAlignment(Alignment):
    @classmethod
    def load(cls, path: Union[str, bytes, os.PathLike[str]]) -> TrimmedAlignment: ...
    def __init__(
        self,
        names: Sequence[bytes],
        sequences: Sequence[str],
        sequences_mask: Optional[Sequence[bool]] = None,
        residues_mask: Optional[Sequence[bool]] = None,
    ) -> None: ...
    def original_alignment(self) -> Alignment: ...
    def terminal_only(self) -> TrimmedAlignment: ...
    def copy(self) -> TrimmedAlignment: ...
    @property
    def residues_mask(self) -> List[bool]: ...
    @property
    def sequences_mask(self) -> List[bool]: ...


# -- Trimmer classes ---------------------------------------------------------

TRIMMER_BACKEND = Literal["detect", "sse", None]
class BaseTrimmer:
    def __init__(self, *, backend: TRIMMER_BACKEND = "detect") -> None: ...
    def trim(self, alignment: Alignment, matrix: Optional[SimilarityMatrix] = None) -> TrimmedAlignment: ...


AUTOMATIC_TRIMMER_METHODS = Literal["strict", "strictplus", "gappyout", "nogaps", "noallgaps", "automated1"]
class AutomaticTrimmer(BaseTrimmer):
    def __init__(self, method: AUTOMATIC_TRIMMER_METHODS = "strict", *, backend: TRIMMER_BACKEND = "detect") -> None: ...


class ManualTrimmer(BaseTrimmer):
    def __init__(
        self,
        *,
        backend: TRIMMER_BACKEND = "detect",
        gap_threshold: Optional[float] = None,
        gap_absolute_threshold: Optional[int] = None,
        similarity_threshold: Optional[float] = None,
        consistency_threshold: Optional[float] = None,
        conservation_percentage: Optional[float] = None,
    ) -> None: ...

# -- Misc classes ------------------------------------------------------------


class SimilarityMatrix:
    @classmethod
    def aa(cls) -> SimilarityMatrix: ...
    @classmethod
    def nt(cls, degenerated: bool =False) -> SimilarityMatrix: ...
    def __init__(self, alphabet: str, matrix: Sequence[Sequence[float]]) -> None: ...
    def __len__(self) -> int: ...
    def distance(self, a: str, b: str) -> float: ...
    def similarity(self, a: str, b: str) -> float: ...
