from typing import List, Optional, Sequence, Set, Tuple, Union

from django.db.backends.base.base import BaseDatabaseWrapper
from django.db.migrations.migration import Migration
from typing_extensions import Protocol

from .loader import MigrationLoader
from .recorder import MigrationRecorder
from .state import ProjectState

class _ProgressCallbackT(Protocol):
    def __call__(self, __action: str, __migration: Optional[Migration] = ..., __fake: Optional[bool] = ...) -> None: ...

class MigrationExecutor:
    connection: BaseDatabaseWrapper = ...
    loader: MigrationLoader = ...
    recorder: MigrationRecorder = ...
    progress_callback: Optional[_ProgressCallbackT] = ...
    def __init__(
        self,
        connection: Optional[BaseDatabaseWrapper],
        progress_callback: Optional[_ProgressCallbackT] = ...,
    ) -> None: ...
    def migration_plan(
        self, targets: Union[Sequence[Tuple[str, Optional[str]]], Set[Tuple[str, str]]], clean_start: bool = ...
    ) -> List[Tuple[Migration, bool]]: ...
    def migrate(
        self,
        targets: Optional[Sequence[Tuple[str, Optional[str]]]],
        plan: Optional[Sequence[Tuple[Migration, bool]]] = ...,
        state: Optional[ProjectState] = ...,
        fake: bool = ...,
        fake_initial: bool = ...,
    ) -> ProjectState: ...
    def apply_migration(
        self, state: ProjectState, migration: Migration, fake: bool = ..., fake_initial: bool = ...
    ) -> ProjectState: ...
    def record_migration(self, migration: Migration) -> None: ...
    def unapply_migration(self, state: ProjectState, migration: Migration, fake: bool = ...) -> ProjectState: ...
    def check_replacements(self) -> None: ...
    def detect_soft_applied(
        self, project_state: Optional[ProjectState], migration: Migration
    ) -> Tuple[bool, ProjectState]: ...
