from collections.abc import Callable, Iterable
from types import TracebackType
from typing import Any, TypeVar

from django.apps import AppConfig
from django.db.backends.base.base import BaseDatabaseWrapper
from django.db.models import Model
from django.utils.connection import BaseConnectionHandler
from django.utils.functional import cached_property
from typing_extensions import override

DEFAULT_DB_ALIAS: str
DJANGO_VERSION_PICKLE_KEY: str

class Error(Exception): ...
class InterfaceError(Error): ...
class DatabaseError(Error): ...
class DataError(DatabaseError): ...
class OperationalError(DatabaseError): ...
class IntegrityError(DatabaseError): ...
class InternalError(DatabaseError): ...
class ProgrammingError(DatabaseError): ...
class NotSupportedError(DatabaseError): ...

_F = TypeVar("_F", bound=Callable[..., Any])

class DatabaseErrorWrapper:
    def __init__(self, wrapper: Any) -> None: ...
    def __del__(self) -> None: ...
    def __enter__(self) -> None: ...
    def __exit__(
        self,
        exc_type: type[BaseException] | None,
        exc_value: BaseException | None,
        traceback: TracebackType | None,
    ) -> None: ...
    def __call__(self, func: _F) -> _F: ...

def load_backend(backend_name: str) -> Any: ...

class ConnectionHandler(BaseConnectionHandler[BaseDatabaseWrapper]):
    @override
    def configure_settings(self, databases: dict[str, Any] | None) -> dict[str, Any]: ...
    @property
    def databases(self) -> dict[str, dict[str, Any]]: ...
    @override
    def create_connection(self, alias: str) -> BaseDatabaseWrapper: ...

class ConnectionRouter:
    def __init__(self, routers: Iterable[Any] | None = None) -> None: ...
    @cached_property
    def routers(self) -> list[Any]: ...
    def db_for_read(self, model: type[Model], **hints: Any) -> str: ...
    def db_for_write(self, model: type[Model], **hints: Any) -> str: ...
    def allow_relation(self, obj1: Model, obj2: Model, **hints: Any) -> bool: ...
    def allow_migrate(self, db: str, app_label: str, **hints: Any) -> bool: ...
    def allow_migrate_model(self, db: str, model: type[Model]) -> bool: ...
    def get_migratable_models(
        self, app_config: AppConfig, db: str, include_auto_created: bool = False
    ) -> list[type[Model]]: ...
