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

from django import forms
from django.core import checks
from django.core.exceptions import ValidationError
from django.forms.renderers import BaseRenderer
from django.forms.utils import ErrorList, _DataT, _FilesT
from django.utils.functional import cached_property
from wagtail.blocks.definition_lookup import (
    BlockDefinitionLookup,
    BlockDefinitionLookupBuilder,
)

__all__ = [
    "BaseBlock",
    "Block",
    "BoundBlock",
    "DeclarativeSubBlocksMetaclass",
    "BlockWidget",
    "BlockField",
]

DECONSTRUCT_ALIASES: dict[type, str]

def get_error_json_data(error: ValidationError) -> dict[str, Any]: ...
def get_error_list_json_data(error_list: ErrorList) -> list[str]: ...
def get_help_icon() -> str: ...

class BaseBlock(type):
    def __new__(mcs, name: str, bases: tuple[type, ...], attrs: dict[str, Any]) -> BaseBlock: ...

class Block(metaclass=BaseBlock):
    name: str
    creation_counter: int
    definition_registry: dict[str, Block]
    definition_prefix: str
    TEMPLATE_VAR: str
    DEFAULT_PREVIEW_TEMPLATE: str
    MUTABLE_META_ATTRIBUTES: list[str]
    label: str
    meta: Block.Meta

    class Meta:
        label: str | None
        icon: str
        classname: str | None
        group: str

    def __new__(cls, *args: Any, **kwargs: Any) -> Self: ...
    def __init__(self, **kwargs: Any) -> None: ...
    @classmethod
    def construct_from_lookup(cls, lookup: BlockDefinitionLookup, *args: Any, **kwargs: Any) -> Block: ...
    def set_name(self, name: str) -> None: ...
    def set_meta_options(self, opts: dict[str, Any]) -> None: ...
    def value_from_datadict(self, data: _DataT, files: _FilesT, prefix: str) -> Any: ...
    def value_omitted_from_data(self, data: _DataT, files: _FilesT, name: str) -> bool: ...
    def bind(
        self,
        value: Any,
        prefix: str | None = ...,
        errors: ValidationError | None = ...,
    ) -> BoundBlock: ...
    def get_default(self) -> Any: ...
    def clean(self, value: Any) -> Any: ...
    def normalize(self, value: Any) -> Any: ...
    def to_python(self, value: Any) -> Any: ...
    def bulk_to_python(self, values: list[Any]) -> list[Any]: ...
    def get_prep_value(self, value: Any) -> Any: ...
    def get_form_state(self, value: Any) -> Any: ...
    def get_context(self, value: Any, parent_context: dict[str, Any] | None = ...) -> dict[str, Any]: ...
    def get_template(self, value: Any = ..., context: dict[str, Any] | None = ...) -> str | None: ...
    def render(self, value: Any, context: dict[str, Any] | None = ...) -> str: ...
    def get_preview_context(self, value: Any, parent_context: dict[str, Any] | None = ...) -> dict[str, Any]: ...
    def get_preview_template(self, value: Any = ..., context: dict[str, Any] | None = ...) -> str: ...
    def get_preview_value(self) -> Any: ...
    @cached_property
    def is_previewable(self) -> bool: ...
    def get_description(self) -> str: ...
    def get_api_representation(self, value: Any, context: dict[str, Any] | None = ...) -> Any: ...
    def render_basic(self, value: Any, context: dict[str, Any] | None = ...) -> str: ...
    def get_searchable_content(self, value: Any) -> list[str]: ...
    def extract_references(self, value: Any) -> Iterable[tuple[type, str, str, str]]: ...
    def get_block_by_content_path(self, value: Any, path_elements: list[str]) -> BoundBlock | None: ...
    def check(self, **kwargs: Any) -> list[checks.Error]: ...
    def id_for_label(self, prefix: str) -> str | None: ...
    @property
    def required(self) -> bool: ...
    @cached_property
    def canonical_module_path(self) -> str: ...
    def deconstruct(self) -> tuple[str, tuple[Any, ...], dict[str, Any]]: ...
    def deconstruct_with_lookup(
        self, lookup: BlockDefinitionLookupBuilder
    ) -> tuple[str, tuple[Any, ...], dict[str, Any]]: ...
    def __eq__(self, other: object) -> bool: ...
    __hash__: None  # type: ignore[assignment]

class BoundBlock:
    block: Block
    value: Any
    prefix: str | None
    errors: ValidationError | None
    def __init__(
        self,
        block: Block,
        value: Any,
        prefix: str | None = ...,
        errors: ValidationError | None = ...,
    ) -> None: ...
    def render(self, context: dict[str, Any] | None = ...) -> str: ...
    def render_as_block(self, context: dict[str, Any] | None = ...) -> str: ...
    def id_for_label(self) -> str | None: ...

class DeclarativeSubBlocksMetaclass(BaseBlock):
    def __new__(mcs, name: str, bases: tuple[type, ...], attrs: dict[str, Any]) -> DeclarativeSubBlocksMetaclass: ...

class BlockWidget(forms.Widget):
    block_def: Block
    def __init__(self, block_def: Block, attrs: dict[str, str] | None = ...) -> None: ...
    @property
    def js_context(self) -> Any: ...
    @property
    def block_json(self) -> str: ...
    def id_for_label(self, prefix: str) -> str | None: ...  # type: ignore[override]
    def render_with_errors(
        self,
        name: str,
        value: Any,
        attrs: dict[str, str] | None = ...,
        errors: ErrorList | None = ...,
        renderer: BaseRenderer | None = ...,
    ) -> str: ...
    def render(  # type: ignore[override]
        self,
        name: str,
        value: Any,
        attrs: dict[str, str] | None = ...,
        renderer: BaseRenderer | None = ...,
    ) -> str: ...
    @cached_property
    def media(self) -> forms.Media: ...  # type: ignore[override]
    def value_from_datadict(self, data: _DataT, files: _FilesT, name: str) -> Any: ...
    def value_omitted_from_data(self, data: _DataT, files: _FilesT, name: str) -> bool: ...

class BlockField(forms.Field):
    block: Block
    def __init__(self, block: Block | None = ..., **kwargs: Any) -> None: ...
    def clean(self, value: Any) -> Any: ...
    def has_changed(self, initial_value: Any, data_value: Any) -> bool: ...
