from collections.abc import Iterable, Iterator, Sequence
from contextlib import contextmanager
from typing import Any

from django.apps import AppConfig
from django.apps.registry import Apps
from django.db.models.base import Model
from django.db.models.fields import Field
from django.db.models.manager import Manager
from django.utils.functional import cached_property

class AppConfigStub(AppConfig):
    def __init__(self, label: str) -> None: ...

class ModelState:
    name: str
    app_label: str
    fields: dict[str, Field]
    options: dict[str, Any]
    bases: Sequence[type[Model] | str]
    managers: list[tuple[str, Manager]]
    def __init__(
        self,
        app_label: str,
        name: str,
        fields: list[tuple[str, Field]] | dict[str, Field],
        options: dict[str, Any] | None = ...,
        bases: Sequence[type[Model] | str] | None = ...,
        managers: list[tuple[str, Manager]] | None = ...,
    ) -> None: ...
    def clone(self) -> ModelState: ...
    def construct_managers(self) -> Iterator[tuple[str, Manager]]: ...
    @classmethod
    def from_model(cls, model: type[Model], exclude_rels: bool = ...) -> ModelState: ...
    def get_field(self, field_name: str) -> Field: ...
    @cached_property
    def name_lower(self) -> str: ...
    def render(self, apps: Apps) -> Any: ...
    def get_index_by_name(self, name: str) -> Any: ...
    def get_constraint_by_name(self, name: str) -> Any: ...
    def __eq__(self, other: object) -> bool: ...

def get_related_models_tuples(model: type[Model]) -> set[tuple[str, str]]: ...
def get_related_models_recursive(model: type[Model]) -> set[tuple[str, str]]: ...

class ProjectState:
    is_delayed: bool
    models: dict[Any, Any]
    real_apps: set[str]
    def __init__(
        self, models: dict[tuple[str, str], ModelState] | None = ..., real_apps: set[str] | None = ...
    ) -> None: ...
    @property
    def relations(self) -> Any: ...
    def add_model(self, model_state: ModelState) -> None: ...
    @cached_property
    def apps(self) -> StateApps: ...
    def clear_delayed_apps_cache(self) -> None: ...
    def clone(self) -> ProjectState: ...
    @classmethod
    def from_apps(cls, apps: Apps) -> ProjectState: ...
    def reload_model(self, app_label: str, model_name: str, delay: bool = ...) -> None: ...
    def reload_models(self, models: list[Any], delay: bool = ...) -> None: ...
    def remove_model(self, app_label: str, model_name: str) -> None: ...
    def rename_model(self, app_label: str, old_name: str, new_name: str) -> None: ...
    def alter_model_options(
        self, app_label: str, model_name: str, options: dict[str, Any], option_keys: Iterable[str] | None = ...
    ) -> None: ...
    def remove_model_options(self, app_label: str, model_name: str, option_name: str, value_to_remove: Any) -> None: ...
    def alter_model_managers(self, app_label: str, model_name: str, managers: list[tuple[str, Manager]]) -> None: ...
    def add_index(self, app_label: str, model_name: str, index: Any) -> None: ...
    def remove_index(self, app_label: str, model_name: str, index_name: str) -> None: ...
    def rename_index(self, app_label: str, model_name: str, old_index_name: str, new_index_name: str) -> None: ...
    def add_constraint(self, app_label: str, model_name: str, constraint: Any) -> None: ...
    def remove_constraint(self, app_label: str, model_name: str, constraint_name: str) -> None: ...
    def add_field(self, app_label: str, model_name: str, name: str, field: Field, preserve_default: Any) -> None: ...
    def remove_field(self, app_label: str, model_name: str, name: str) -> None: ...
    def alter_field(self, app_label: str, model_name: str, name: str, field: Field, preserve_default: Any) -> None: ...
    def rename_field(self, app_label: str, model_name: str, old_name: str, new_name: str) -> None: ...
    def update_model_field_relation(
        self, model: type[Model], model_key: tuple[str, str], field_name: str, field: Field, concretes: Any
    ) -> None: ...
    def resolve_model_field_relations(
        self, model_key: tuple[str, str], field_name: str, field: Field, concretes: Any | None = ...
    ) -> None: ...
    def resolve_model_relations(self, model_key: tuple[str, str], concretes: Any | None = ...) -> None: ...
    def resolve_fields_and_relations(self) -> None: ...
    def get_concrete_model_key(self, model: type[Model]) -> Any: ...

class StateApps(Apps):
    real_models: list[ModelState]
    def __init__(
        self, real_apps: list[str], models: dict[tuple[str, str], ModelState], ignore_swappable: bool = ...
    ) -> None: ...
    @contextmanager
    def bulk_update(self) -> Iterator[None]: ...
    def clone(self) -> StateApps: ...
    def render_multiple(self, model_states: list[ModelState]) -> None: ...
    def register_model(self, app_label: str, model: type[Model]) -> None: ...
    def unregister_model(self, app_label: str, model_name: str) -> None: ...
