from collections.abc import Iterable, Iterator
from typing import Any
import collections

from django import forms
from django.core import checks
from django.core.exceptions import ValidationError
from django.forms.utils import ErrorList, _DataT, _FilesT
from django.utils.functional import cached_property
from django.utils.safestring import SafeString
from telepath import Adapter

from .base import Block, BoundBlock, DeclarativeSubBlocksMetaclass
from .definition_lookup import BlockDefinitionLookup, BlockDefinitionLookupBuilder

__all__ = [
    "BaseStructBlock",
    "StructBlock",
    "StructValue",
    "StructBlockValidationError",
]

class StructBlockValidationError(ValidationError):
    non_block_errors: ErrorList
    block_errors: dict[str, ValidationError]
    def __init__(
        self,
        block_errors: dict[str, ValidationError | ErrorList | list[ValidationError]] | None = None,
        non_block_errors: ErrorList | list[str | ValidationError] | None = None,
    ) -> None: ...
    def as_json_data(self) -> dict[str, Any]: ...

class StructValue(collections.OrderedDict[str, Any]):
    block: Block
    def __init__(self, block: Block, *args: Iterable[tuple[str, Any]] | dict[str, Any]) -> None: ...
    def __html__(self) -> str: ...
    def render_as_block(self, context: dict[str, Any] | None = None) -> str: ...
    @cached_property
    def bound_blocks(self) -> collections.OrderedDict[str, BoundBlock]: ...
    def __reduce__(self) -> tuple[type[StructValue], tuple[Block], None, None, Iterator[tuple[str, Any]]]: ...

class PlaceholderBoundBlock(BoundBlock):
    def render_form(self) -> SafeString: ...

class BaseStructBlock(Block):
    search_index: bool
    child_blocks: collections.OrderedDict[str, Block]
    _constructor_kwargs: dict[str, Any]
    def __init__(
        self, local_blocks: Iterable[tuple[str, Block]] | None = None, search_index: bool = True, **kwargs: Any
    ) -> None: ...
    @classmethod
    def construct_from_lookup(
        cls, lookup: BlockDefinitionLookup, child_blocks: list[tuple[str, int]] | None = None, **kwargs: Any
    ) -> BaseStructBlock: ...
    def get_default(self) -> StructValue: ...
    def value_from_datadict(self, data: _DataT, files: _FilesT, prefix: str) -> StructValue: ...
    def value_omitted_from_data(self, data: _DataT, files: _FilesT, prefix: str) -> bool: ...
    def clean(self, value: StructValue | dict[str, Any]) -> StructValue: ...
    def to_python(self, value: dict[str, Any] | StructValue) -> StructValue: ...
    def bulk_to_python(self, values: list[dict[str, Any]]) -> list[StructValue]: ...
    def _to_struct_value(self, block_items: Iterable[tuple[str, Any]] | dict[str, Any]) -> StructValue: ...
    def get_prep_value(self, value: StructValue | dict[str, Any]) -> dict[str, Any]: ...
    def normalize(self, value: StructValue | dict[str, Any]) -> StructValue: ...
    def get_form_state(self, value: StructValue | dict[str, Any]) -> dict[str, Any]: ...
    def get_api_representation(
        self, value: StructValue | dict[str, Any], context: dict[str, Any] | None = None
    ) -> dict[str, Any]: ...
    def get_searchable_content(self, value: StructValue | dict[str, Any]) -> list[str]: ...
    def extract_references(self, value: StructValue | dict[str, Any]) -> Iterator[tuple[type, str, str, str]]: ...
    def get_block_by_content_path(
        self, value: StructValue | dict[str, Any], path_elements: list[str]
    ) -> BoundBlock | None: ...
    def deconstruct(self) -> tuple[str, list[Any], dict[str, Any]]: ...
    def deconstruct_with_lookup(
        self, lookup: BlockDefinitionLookupBuilder
    ) -> tuple[str, list[Any], dict[str, Any]]: ...
    def check(self, **kwargs: Any) -> list[checks.Error]: ...
    def render_basic(self, value: StructValue, context: dict[str, Any] | None = None) -> SafeString: ...
    def render_form_template(self) -> SafeString: ...
    def get_description(self) -> str: ...
    def get_form_context(
        self, value: StructValue | dict[str, Any], prefix: str = "", errors: ValidationError | None = None
    ) -> dict[str, Any]: ...
    @cached_property
    def _has_default(self) -> bool: ...

    class Meta:
        default: dict[str, Any]
        form_classname: str
        form_template: str | None
        value_class: type[StructValue]
        label_format: str | None
        icon: str
        collapsed: bool

class StructBlock(BaseStructBlock, metaclass=DeclarativeSubBlocksMetaclass):
    base_blocks: collections.OrderedDict[str, Block]

class StructBlockAdapter(Adapter):
    js_constructor: str
    def js_args(self, block: StructBlock) -> list[Any]: ...
    @cached_property
    def media(self) -> forms.Media: ...
