from typing import Any, Callable, Dict, List, Optional, Tuple, Type, Union
from uuid import UUID

from django.core.checks.messages import Error, Warning
from django.db.backends.sqlite3.base import DatabaseWrapper
from django.db.models.base import Model
from django.db.models.expressions import Col
from django.db.models.fields import Field
from django.db.models.fields.related_lookups import RelatedIsNull
from django.db.models.fields.reverse_related import (ForeignObjectRel,
                                                     ManyToManyRel,
                                                     ManyToOneRel, OneToOneRel)
from django.db.models.lookups import FieldGetDbPrepValueMixin
from django.db.models.query import QuerySet
from django.db.models.query_utils import PathInfo, Q
from django.db.models.sql.where import WhereNode
from django.forms.fields import Field
from django.forms.models import ModelChoiceField, ModelMultipleChoiceField

from . import Field
from .mixins import FieldCacheMixin
from .related_descriptors import (ForwardManyToOneDescriptor,
                                  ForwardOneToOneDescriptor,
                                  ManyToManyDescriptor,
                                  ReverseManyToOneDescriptor,
                                  ReverseOneToOneDescriptor)
from .related_lookups import (RelatedExact, RelatedGreaterThan,
                              RelatedGreaterThanOrEqual, RelatedIn,
                              RelatedIsNull, RelatedLessThan,
                              RelatedLessThanOrEqual)
from .reverse_related import (ForeignObjectRel, ManyToManyRel, ManyToOneRel,
                              OneToOneRel)

RECURSIVE_RELATIONSHIP_CONSTANT: str

def resolve_relation(
    scope_model: Type[Model], relation: Union[Type[Model], str]
) -> Union[Type[Model], str]: ...
def lazy_related_operation(
    function: Callable, model: Type[Model], *related_models: Any, **kwargs: Any
) -> None: ...

class RelatedField(FieldCacheMixin, Field):
    one_to_many: bool = ...
    one_to_one: bool = ...
    many_to_many: bool = ...
    many_to_one: bool = ...
    def related_model(self) -> Union[Type[Model], str]: ...
    def check(self, **kwargs: Any) -> List[Error]: ...
    def db_type(self, connection: DatabaseWrapper) -> None: ...
    opts: Any = ...
    def contribute_to_class(
        self,
        cls: Type[Model],
        name: str,
        private_only: bool = ...,
        **kwargs: Any
    ) -> None: ...
    def deconstruct(
        self
    ) -> Tuple[Optional[str], str, List[Any], Dict[str, str]]: ...
    def get_forward_related_filter(
        self, obj: Model
    ) -> Dict[str, Union[int, UUID]]: ...
    def get_reverse_related_filter(self, obj: Model) -> Q: ...
    @property
    def swappable_setting(self) -> Optional[str]: ...
    name: Any = ...
    verbose_name: Any = ...
    def set_attributes_from_rel(self) -> None: ...
    def do_related_class(
        self, other: Type[Model], cls: Type[Model]
    ) -> None: ...
    def get_limit_choices_to(self) -> Dict[str, int]: ...
    def formfield(self, **kwargs: Any) -> Field: ...
    def related_query_name(self) -> str: ...
    @property
    def target_field(self) -> Field: ...
    def get_cache_name(self) -> str: ...

class ForeignObject(RelatedField):
    many_to_many: bool = ...
    many_to_one: bool = ...
    one_to_many: bool = ...
    one_to_one: bool = ...
    requires_unique_target: bool = ...
    related_accessor_class: Any = ...
    forward_related_accessor_class: Any = ...
    rel_class: Any = ...
    from_fields: Any = ...
    to_fields: Any = ...
    swappable: Any = ...
    def __init__(
        self,
        to: Union[Type[Model], str],
        on_delete: Callable,
        from_fields: Union[List[str], Tuple[str, str]],
        to_fields: Union[List[None], List[str], Tuple[str, str]],
        rel: Optional[ForeignObjectRel] = ...,
        related_name: None = ...,
        related_query_name: None = ...,
        limit_choices_to: None = ...,
        parent_link: bool = ...,
        swappable: bool = ...,
        **kwargs: Any
    ) -> None: ...
    def check(self, **kwargs: Any) -> List[Any]: ...
    def deconstruct(
        self
    ) -> Tuple[
        Optional[str],
        str,
        List[Any],
        Dict[str, Any],
    ]: ...
    def resolve_related_fields(self) -> List[Tuple[Field, Field]]: ...
    @property
    def related_fields(self) -> List[Tuple[Field, Field]]: ...
    @property
    def reverse_related_fields(self) -> List[Tuple[Field, Field]]: ...
    @property
    def local_related_fields(self) -> Tuple[Field]: ...
    @property
    def foreign_related_fields(self) -> Tuple[Field]: ...
    def get_local_related_value(
        self, instance: Model
    ) -> Tuple[Optional[int]]: ...
    def get_foreign_related_value(
        self, instance: Model
    ) -> Tuple[Optional[int]]: ...
    @staticmethod
    def get_instance_value_for_fields(
        instance: Model, fields: Tuple[Field]
    ) -> Tuple[Optional[int]]: ...
    def get_attname_column(self) -> Tuple[str, None]: ...
    def get_joining_columns(
        self, reverse_join: bool = ...
    ) -> Tuple[Tuple[str, str]]: ...
    def get_reverse_joining_columns(self) -> Tuple: ...
    def get_extra_descriptor_filter(
        self, instance: Model
    ) -> Dict[Any, Any]: ...
    def get_extra_restriction(
        self, where_class: Type[WhereNode], alias: str, related_alias: str
    ) -> None: ...
    def get_path_info(
        self, filtered_relation: None = ...
    ) -> List[PathInfo]: ...
    def get_reverse_path_info(self, filtered_relation: Optional[Any] = ...): ...
    @classmethod
    def get_lookups(
        cls
    ) -> Dict[str, Type[Union[RelatedIsNull, FieldGetDbPrepValueMixin]]]: ...
    def contribute_to_class(
        self,
        cls: Type[Model],
        name: str,
        private_only: bool = ...,
        **kwargs: Any
    ) -> None: ...
    def contribute_to_related_class(
        self, cls: Type[Model], related: ForeignObjectRel
    ) -> None: ...

class ForeignKey(ForeignObject):
    many_to_many: bool = ...
    many_to_one: bool = ...
    one_to_many: bool = ...
    one_to_one: bool = ...
    rel_class: Any = ...
    empty_strings_allowed: bool = ...
    default_error_messages: Any = ...
    description: Any = ...
    db_constraint: Any = ...
    def __init__(
        self,
        to: Union[Type[Model], str],
        on_delete: Callable,
        related_name: Optional[str] = ...,
        related_query_name: None = ...,
        limit_choices_to: Optional[
            Union[Callable, Dict[str, Union[int, str]]]
        ] = ...,
        parent_link: bool = ...,
        to_field: Optional[str] = ...,
        db_constraint: bool = ...,
        **kwargs: Any
    ) -> None: ...
    def check(self, **kwargs: Any) -> List[Warning]: ...
    def deconstruct(
        self
    ) -> Tuple[
        Optional[str],
        str,
        List[Any],
        Dict[str, Union[Callable, Dict[str, Union[int, str]], str]],
    ]: ...
    def to_python(self, value: Union[int, str]) -> int: ...
    @property
    def target_field(self) -> Field: ...
    def get_reverse_path_info(
        self, filtered_relation: None = ...
    ) -> List[PathInfo]: ...
    def validate(
        self, value: Union[int, str], model_instance: Model
    ) -> None: ...
    def get_attname(self) -> str: ...
    def get_attname_column(self) -> Tuple[str, str]: ...
    def get_default(self) -> Optional[int]: ...
    def get_db_prep_save(
        self,
        value: Optional[Union[int, str, UUID]],
        connection: DatabaseWrapper,
    ) -> Optional[Union[int, str]]: ...
    def get_db_prep_value(
        self,
        value: Union[int, str, UUID],
        connection: DatabaseWrapper,
        prepared: bool = ...,
    ) -> Union[int, str]: ...
    def contribute_to_related_class(
        self, cls: Type[Model], related: ManyToOneRel
    ) -> None: ...
    def formfield(
        self, *, using: Optional[Any] = ..., **kwargs: Any
    ) -> ModelChoiceField: ...
    def db_check(self, connection: DatabaseWrapper) -> List[Any]: ...
    def db_type(self, connection: DatabaseWrapper) -> str: ...
    def db_parameters(
        self, connection: DatabaseWrapper
    ) -> Dict[str, Union[List[Any], str]]: ...
    def convert_empty_strings(
        self, value: Any, expression: Any, connection: Any
    ): ...
    def get_db_converters(self, connection: DatabaseWrapper) -> List[Any]: ...
    def get_col(
        self,
        alias: str,
        output_field: Optional[Union[Field, reverse_related.OneToOneRel]] = ...,
    ) -> Col: ...

class OneToOneField(ForeignKey):
    many_to_many: bool = ...
    many_to_one: bool = ...
    one_to_many: bool = ...
    one_to_one: bool = ...
    related_accessor_class: Any = ...
    forward_related_accessor_class: Any = ...
    rel_class: Any = ...
    description: Any = ...
    def __init__(
        self,
        to: Union[Type[Model], str],
        on_delete: Callable,
        to_field: Optional[str] = ...,
        **kwargs: Any
    ) -> None: ...
    def deconstruct(
        self
    ) -> Tuple[
        Optional[str], str, List[Any], Dict[str, Union[Callable, bool, str]]
    ]: ...
    def formfield(self, **kwargs: Any) -> None: ...
    def save_form_data(
        self, instance: Model, data: Optional[Model]
    ) -> None: ...

def create_many_to_many_intermediary_model(field: Any, klass: Any): ...

class ManyToManyField(RelatedField):
    many_to_many: bool = ...
    many_to_one: bool = ...
    one_to_many: bool = ...
    one_to_one: bool = ...
    rel_class: Any = ...
    description: Any = ...
    has_null_arg: Any = ...
    db_table: Any = ...
    swappable: Any = ...
    def __init__(
        self,
        to: Union[Type[Model], str],
        related_name: Optional[str] = ...,
        related_query_name: Optional[str] = ...,
        limit_choices_to: Optional[Callable] = ...,
        symmetrical: Optional[bool] = ...,
        through: Optional[str] = ...,
        through_fields: Optional[Tuple[str, str]] = ...,
        db_constraint: bool = ...,
        db_table: None = ...,
        swappable: bool = ...,
        **kwargs: Any
    ) -> None: ...
    def check(self, **kwargs: Any) -> List[Any]: ...
    def deconstruct(
        self
    ) -> Tuple[Optional[str], str, List[Any], Dict[str, str]]: ...
    def get_path_info(
        self, filtered_relation: None = ...
    ) -> List[PathInfo]: ...
    def get_reverse_path_info(
        self, filtered_relation: None = ...
    ) -> List[PathInfo]: ...
    m2m_db_table: Any = ...
    def contribute_to_class(
        self, cls: Type[Model], name: str, **kwargs: Any
    ) -> None: ...
    m2m_column_name: Any = ...
    m2m_reverse_name: Any = ...
    m2m_field_name: Any = ...
    m2m_reverse_field_name: Any = ...
    m2m_target_field_name: Any = ...
    m2m_reverse_target_field_name: Any = ...
    def contribute_to_related_class(
        self, cls: Type[Model], related: ManyToManyRel
    ) -> None: ...
    def set_attributes_from_rel(self) -> None: ...
    def value_from_object(self, obj: Model) -> List[Model]: ...
    def save_form_data(self, instance: Model, data: QuerySet) -> None: ...
    def formfield(
        self, *, using: Optional[Any] = ..., **kwargs: Any
    ) -> ModelMultipleChoiceField: ...
    def db_check(self, connection: Any): ...
    def db_type(self, connection: Any): ...
    def db_parameters(self, connection: DatabaseWrapper) -> Dict[str, None]: ...
