import logging
import sys
from argparse import ArgumentParser
from collections.abc import Callable, Iterable, Iterator, Sequence
from contextlib import AbstractContextManager
from typing import Any, Literal
from unittest import TestCase, TestLoader, TestResult, TestSuite, TextTestResult, TextTestRunner

from django.db.backends.base.base import BaseDatabaseWrapper
from django.test.testcases import SimpleTestCase
from django.test.testcases import TestCase as DjangoTestCase
from django.test.utils import TimeKeeperProtocol
from typing_extensions import override

class QueryFormatter(logging.Formatter): ...

class DebugSQLTextTestResult(TextTestResult):
    logger: logging.Logger
    def __init__(self, stream: Any, descriptions: bool, verbosity: int) -> None: ...
    handler: logging.StreamHandler[Any]
    @override
    def startTest(self, test: TestCase) -> None: ...
    @override
    def stopTest(self, test: TestCase) -> None: ...
    @override
    def addError(self, test: Any, err: Any) -> None: ...
    @override
    def addFailure(self, test: Any, err: Any) -> None: ...

class PDBDebugResult(TextTestResult):
    def debug(self, error: tuple[type[BaseException], BaseException, Any]) -> None: ...

class DummyList:
    __slots__ = ()
    def append(self, item: Any) -> None: ...

class RemoteTestResult(TestResult):
    events: list[Any]
    def __init__(self, *args: Any, **kwargs: Any) -> None: ...
    @property
    def test_index(self) -> int: ...
    def _confirm_picklable(self, obj: Any) -> None: ...
    def check_picklable(self, test: Any, err: Any) -> None: ...
    def check_subtest_picklable(self, test: Any, subtest: Any) -> None: ...
    @override
    def startTestRun(self) -> None: ...
    @override
    def stopTestRun(self) -> None: ...
    @override
    def startTest(self, test: Any) -> None: ...
    @override
    def stopTest(self, test: Any) -> None: ...
    if sys.version_info >= (3, 12):
        @override
        def addDuration(self, test: Any, elapsed: Any) -> None: ...
    else:
        def addDuration(self, test: Any, elapsed: Any) -> None: ...
    @override
    def addError(self, test: Any, err: Any) -> None: ...
    @override
    def addFailure(self, test: Any, err: Any) -> None: ...
    @override
    def addSubTest(self, test: Any, subtest: Any, err: Any) -> None: ...
    @override
    def addSuccess(self, test: Any) -> None: ...
    @override
    def addSkip(self, test: Any, reason: Any) -> None: ...
    @override
    def addExpectedFailure(self, test: Any, err: Any) -> None: ...
    @override
    def addUnexpectedSuccess(self, test: Any) -> None: ...
    @override
    def wasSuccessful(self) -> bool: ...

class RemoteTestRunner:
    resultclass: Any
    failfast: bool
    buffer: bool
    def __init__(self, failfast: bool = ..., resultclass: Any | None = ..., buffer: bool = ...) -> None: ...
    def run(self, test: Any) -> Any: ...

def get_max_test_processes() -> int: ...
def parallel_type(value: str) -> int | Literal["auto"]: ...

class ParallelTestSuite(TestSuite):
    init_worker: Callable[..., Any]
    process_setup: Callable[..., Any]
    process_setup_args: tuple[Any, ...]
    run_subsuite: Callable[..., Any]
    runner_class: type[RemoteTestRunner]
    subsuites: list[TestSuite]
    processes: int
    failfast: bool
    debug_mode: bool
    buffer: bool
    initial_settings: dict[str, dict[str, Any]] | None
    serialized_contents: dict[str, str] | None
    used_aliases: set[str] | None
    def __init__(
        self,
        subsuites: list[TestSuite],
        processes: int,
        failfast: bool = ...,
        debug_mode: bool = ...,
        buffer: bool = ...,
    ) -> None: ...
    @override
    def run(self, result: Any) -> Any: ...  # type: ignore[override]
    def handle_event(self, result: Any, tests: list[TestSuite], event: Sequence[Any]) -> None: ...
    def initialize_suite(self) -> None: ...

class Shuffler:
    hash_algorithm: str
    seed: int
    seed_source: str
    def __init__(self, seed: int | None = ...) -> None: ...
    @property
    def seed_display(self) -> str: ...
    def shuffle(self, items: Iterable[Any], key: Callable[[Any], str]) -> list[Any]: ...

class DiscoverRunner:
    test_suite: type[TestSuite]
    parallel_test_suite: type[ParallelTestSuite]
    test_runner: type[TextTestRunner]
    test_loader: TestLoader
    reorder_by: tuple[type[DjangoTestCase], type[SimpleTestCase]]
    pattern: str | None
    top_level: str | None
    verbosity: int
    interactive: bool
    failfast: bool
    keepdb: bool
    reverse: bool
    debug_mode: bool
    debug_sql: bool
    parallel: int
    tags: set[str]
    exclude_tags: set[str]
    pdb: bool
    buffer: bool
    test_name_patterns: set[str] | None
    time_keeper: TimeKeeperProtocol
    shuffle: int | Literal[False]
    logger: logging.Logger | None
    durations: int | None
    def __init__(
        self,
        pattern: str | None = ...,
        top_level: str | None = ...,
        verbosity: int = ...,
        interactive: bool = ...,
        failfast: bool = ...,
        keepdb: bool = ...,
        reverse: bool = ...,
        debug_mode: bool = ...,
        debug_sql: bool = ...,
        parallel: int = ...,
        tags: list[str] | None = ...,
        exclude_tags: list[str] | None = ...,
        test_name_patterns: list[str] | None = ...,
        pdb: bool = ...,
        buffer: bool = ...,
        enable_faulthandler: bool = ...,
        timing: bool = ...,
        shuffle: int | Literal[False] = ...,
        logger: logging.Logger | None = ...,
        durations: int | None = ...,
        **kwargs: Any,
    ) -> None: ...
    @classmethod
    def add_arguments(cls, parser: ArgumentParser) -> None: ...
    @property
    def shuffle_seed(self) -> int | None: ...
    def log(self, msg: str, level: int | None = ...) -> None: ...
    def setup_test_environment(self, **kwargs: Any) -> None: ...
    def setup_shuffler(self) -> None: ...
    def load_with_patterns(self) -> AbstractContextManager[None]: ...
    def load_tests_for_label(self, label: str, discover_kwargs: dict[str, str]) -> TestSuite: ...
    def build_suite(self, test_labels: Sequence[str] | None = ..., **kwargs: Any) -> TestSuite: ...
    def setup_databases(self, **kwargs: Any) -> list[tuple[BaseDatabaseWrapper, str, bool]]: ...
    def get_resultclass(self) -> type[TextTestResult] | None: ...
    def get_test_runner_kwargs(self) -> dict[str, Any]: ...
    def run_checks(self, databases: set[str]) -> None: ...
    def run_suite(self, suite: TestSuite, **kwargs: Any) -> TextTestResult: ...
    def teardown_databases(self, old_config: list[tuple[BaseDatabaseWrapper, str, bool]], **kwargs: Any) -> None: ...
    def teardown_test_environment(self, **kwargs: Any) -> None: ...
    def suite_result(self, suite: TestSuite, result: TextTestResult, **kwargs: Any) -> int: ...
    def _get_databases(self, suite: TestSuite) -> set[str]: ...
    def get_databases(self, suite: TestSuite) -> set[str]: ...
    def run_tests(self, test_labels: list[str], **kwargs: Any) -> int: ...

def try_importing(label: str) -> tuple[bool, bool]: ...
def find_top_level(top_level: str) -> str: ...
def shuffle_tests(tests: Iterable[TestCase], shuffler: Shuffler) -> Iterator[TestCase]: ...
def reorder_test_bin(
    tests: Sequence[TestCase], shuffler: Shuffler | None = ..., reverse: bool = ...
) -> Iterator[TestCase]: ...
def reorder_tests(
    tests: Iterable[TestCase],
    classes: Sequence[type[TestCase]],
    reverse: bool = ...,
    shuffler: Shuffler | None = ...,
) -> Iterator[TestCase]: ...
def partition_suite_by_case(suite: TestSuite) -> list[TestSuite]: ...
def test_match_tags(test: TestCase, tags: set[str], exclude_tags: set[str]) -> bool: ...
def filter_tests_by_tags(tests: Iterable[TestCase], tags: set[str], exclude_tags: set[str]) -> Iterator[TestCase]: ...
