import datetime
from collections.abc import Iterable, Iterator, Mapping, Sequence
from typing import Any, Literal, Protocol, TypeAlias, type_check_only

import _typeshed
from django.core.files.base import File
from django.forms.renderers import BaseRenderer
from django.forms.utils import _DataT, _FilesT
from django.utils.choices import _Choices
from django.utils.datastructures import _ListOrTuple
from django.utils.safestring import SafeString
from typing_extensions import Self, override

_OptAttrs: TypeAlias = dict[str, Any]

class MediaOrderConflictWarning(RuntimeWarning): ...

class MediaAsset:
    element_template: str

    def __init__(self, path: str, **attributes: Any) -> None: ...
    @override
    def __eq__(self, other: object) -> bool: ...
    @override
    def __hash__(self) -> int: ...
    def __html__(self) -> SafeString: ...
    @property
    def path(self) -> str: ...

class Script(MediaAsset):
    element_template: str

    def __init__(self, src: str, **attributes: Any) -> None: ...

class Media:
    def __init__(
        self,
        media: type | None = None,
        css: dict[str, Sequence[str]] | None = None,
        js: Sequence[str] | None = None,
    ) -> None: ...
    def render(self) -> SafeString: ...
    def render_js(self) -> list[SafeString]: ...
    def render_css(self) -> Iterable[SafeString]: ...
    def absolute_path(self, path: str) -> str: ...
    def __getitem__(self, name: str) -> Media: ...
    @staticmethod
    def merge(*lists: Iterable[Any]) -> list[Any]: ...
    def __add__(self, other: Media) -> Media: ...
    def __html__(self) -> SafeString: ...

class MediaDefiningClass(type):
    def __new__(
        mcs: type[_typeshed.Self],  # noqa: TID251
        name: str,
        bases: tuple[type, ...],
        attrs: dict[str, Any],
    ) -> _typeshed.Self: ...  # noqa: TID251

class Widget(metaclass=MediaDefiningClass):
    needs_multipart_form: bool
    is_localized: bool
    is_required: bool
    supports_microseconds: bool
    attrs: _OptAttrs
    template_name: str
    use_fieldset: bool
    def __init__(self, attrs: _OptAttrs | None = None) -> None: ...
    def __deepcopy__(self, memo: dict[int, Any]) -> Self: ...
    @property
    def is_hidden(self) -> bool: ...
    @property
    def media(self) -> Media: ...
    def subwidgets(self, name: str, value: Any, attrs: _OptAttrs | None = None) -> Iterator[dict[str, Any]]: ...
    def format_value(self, value: Any) -> str | None: ...
    def get_context(self, name: str, value: Any, attrs: _OptAttrs | None) -> dict[str, Any]: ...
    def render(
        self, name: str, value: Any, attrs: _OptAttrs | None = None, renderer: BaseRenderer | None = None
    ) -> SafeString: ...
    def build_attrs(self, base_attrs: _OptAttrs, extra_attrs: _OptAttrs | None = None) -> dict[str, Any]: ...
    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: ...
    def id_for_label(self, id_: str) -> str: ...
    def use_required_attribute(self, initial: Any) -> bool: ...

class Input(Widget):
    input_type: str
    template_name: str
    @override
    def get_context(self, name: str, value: Any, attrs: _OptAttrs | None) -> dict[str, Any]: ...

class TextInput(Input):
    input_type: str
    template_name: str

class NumberInput(Input):
    input_type: str
    template_name: str

class EmailInput(Input):
    input_type: str
    template_name: str

class URLInput(Input):
    input_type: str
    template_name: str

class ColorInput(Input):
    input_type: str
    template_name: str

class SearchInput(Input):
    input_type: str
    template_name: str

class TelInput(Input):
    input_type: str
    template_name: str

class PasswordInput(Input):
    render_value: bool
    input_type: str
    template_name: str
    def __init__(self, attrs: _OptAttrs | None = None, render_value: bool = False) -> None: ...
    @override
    def get_context(self, name: str, value: Any, attrs: _OptAttrs | None) -> dict[str, Any]: ...

class HiddenInput(Input):
    input_type: str
    template_name: str

class MultipleHiddenInput(HiddenInput):
    template_name: str
    @override
    def get_context(self, name: str, value: Any, attrs: _OptAttrs | None) -> dict[str, Any]: ...
    @override
    def value_from_datadict(self, data: _DataT, files: _FilesT, name: str) -> Any: ...
    @override
    def format_value(self, value: Any) -> list[str]: ...  # type: ignore[override]

class FileInput(Input):
    allow_multiple_selected: bool
    input_type: str
    template_name: str
    needs_multipart_form: bool
    @override
    def format_value(self, value: Any) -> None: ...
    @override
    def value_from_datadict(self, data: _DataT, files: _FilesT, name: str) -> Any: ...
    @override
    def value_omitted_from_data(self, data: _DataT, files: _FilesT, name: str) -> bool: ...
    @override
    def use_required_attribute(self, initial: Any) -> bool: ...

FILE_INPUT_CONTRADICTION: object

class ClearableFileInput(FileInput):
    clear_checkbox_label: str
    initial_text: str
    input_text: str
    template_name: str
    checked: bool
    def clear_checkbox_name(self, name: str) -> str: ...
    def clear_checkbox_id(self, name: str) -> str: ...
    def is_initial(self, value: File | str | None) -> bool: ...
    @override
    def format_value(self, value: Any) -> Any: ...
    @override
    def get_context(self, name: str, value: Any, attrs: _OptAttrs | None) -> dict[str, Any]: ...
    @override
    def value_from_datadict(self, data: _DataT, files: _FilesT, name: str) -> Any: ...
    @override
    def value_omitted_from_data(self, data: _DataT, files: _FilesT, name: str) -> bool: ...

class Textarea(Widget):
    template_name: str
    def __init__(self, attrs: _OptAttrs | None = None) -> None: ...

class DateTimeBaseInput(TextInput):
    format_key: str
    format: str | None
    supports_microseconds: bool
    def __init__(self, attrs: _OptAttrs | None = None, format: str | None = None) -> None: ...
    @override
    def format_value(self, value: Any) -> str | None: ...

class DateInput(DateTimeBaseInput):
    format_key: str
    template_name: str

class DateTimeInput(DateTimeBaseInput):
    format_key: str
    template_name: str

class TimeInput(DateTimeBaseInput):
    format_key: str
    template_name: str

def boolean_check(v: Any) -> bool: ...

@type_check_only
class _CheckCallable(Protocol):
    def __call__(self, value: Any, /) -> bool: ...

class CheckboxInput(Input):
    check_test: _CheckCallable
    input_type: str
    template_name: str
    def __init__(self, attrs: _OptAttrs | None = None, check_test: _CheckCallable | None = None) -> None: ...
    @override
    def format_value(self, value: Any) -> str | None: ...
    @override
    def get_context(self, name: str, value: Any, attrs: _OptAttrs | None) -> dict[str, Any]: ...
    @override
    def value_from_datadict(self, data: _DataT, files: _FilesT, name: str) -> bool: ...
    @override
    def value_omitted_from_data(self, data: _DataT, files: _FilesT, name: str) -> bool: ...

class ChoiceWidget(Widget):
    allow_multiple_selected: bool
    input_type: str
    template_name: str
    option_template_name: str
    add_id_index: bool
    checked_attribute: Any
    option_inherits_attrs: bool
    choices: _Choices
    def __init__(self, attrs: _OptAttrs | None = None, choices: _Choices = ()) -> None: ...
    @override
    def subwidgets(self, name: str, value: Any, attrs: _OptAttrs | None = None) -> Iterator[dict[str, Any]]: ...
    def options(self, name: str, value: list[str], attrs: _OptAttrs | None = None) -> Iterator[dict[str, Any]]: ...
    def optgroups(
        self, name: str, value: list[str], attrs: _OptAttrs | None = None
    ) -> list[tuple[str | None, list[dict[str, Any]], int | None]]: ...
    def create_option(
        self,
        name: str,
        value: Any,
        label: int | str,
        selected: bool,
        index: int,
        subindex: int | None = None,
        attrs: _OptAttrs | None = None,
    ) -> dict[str, Any]: ...
    @override
    def get_context(self, name: str, value: Any, attrs: _OptAttrs | None) -> dict[str, Any]: ...
    @override
    def id_for_label(self, id_: str, index: str = "0") -> str: ...
    @override
    def value_from_datadict(self, data: _DataT, files: _FilesT, name: str) -> Any: ...
    @override
    def format_value(self, value: Any) -> list[str]: ...  # type: ignore[override]

class Select(ChoiceWidget):
    input_type: str
    template_name: str
    option_template_name: str
    add_id_index: bool
    checked_attribute: Any
    option_inherits_attrs: bool
    @override
    def get_context(self, name: str, value: Any, attrs: _OptAttrs | None) -> dict[str, Any]: ...
    @override
    def use_required_attribute(self, initial: Any) -> bool: ...

class NullBooleanSelect(Select):
    def __init__(self, attrs: _OptAttrs | None = None) -> None: ...
    @override
    def format_value(self, value: Any) -> str: ...  # type: ignore[override]
    @override
    def value_from_datadict(self, data: _DataT, files: _FilesT, name: str) -> bool | None: ...

class SelectMultiple(Select):
    allow_multiple_selected: bool
    @override
    def value_from_datadict(self, data: _DataT, files: _FilesT, name: str) -> Any: ...
    @override
    def value_omitted_from_data(self, data: _DataT, files: _FilesT, name: str) -> bool: ...

class RadioSelect(ChoiceWidget):
    input_type: str
    template_name: str
    option_template_name: str
    @override
    def id_for_label(self, id_: str, index: str | None = None) -> str: ...

class CheckboxSelectMultiple(RadioSelect):
    input_type: str
    template_name: str
    option_template_name: str
    @override
    def use_required_attribute(self, initial: Any) -> bool: ...
    @override
    def value_omitted_from_data(self, data: _DataT, files: _FilesT, name: str) -> bool: ...

class MultiWidget(Widget):
    template_name: str
    widgets: Sequence[Widget]
    def __init__(
        self,
        widgets: dict[str, Widget | type[Widget]] | Sequence[Widget | type[Widget]],
        attrs: _OptAttrs | None = None,
    ) -> None: ...
    @property
    @override
    def is_hidden(self) -> bool: ...
    @override
    def get_context(self, name: str, value: Any, attrs: _OptAttrs | None) -> dict[str, Any]: ...
    @override
    def id_for_label(self, id_: str) -> str: ...
    @override
    def value_from_datadict(self, data: _DataT, files: _FilesT, name: str) -> list[Any]: ...
    @override
    def value_omitted_from_data(self, data: _DataT, files: _FilesT, name: str) -> bool: ...
    def decompress(self, value: Any) -> Any | None: ...
    @property
    @override
    def needs_multipart_form(self) -> bool: ...  # type: ignore[override]

class SplitDateTimeWidget(MultiWidget):
    supports_microseconds: bool
    template_name: str
    widgets: tuple[DateInput, TimeInput]  # pyright: ignore[reportIncompatibleVariableOverride]
    def __init__(
        self,
        attrs: _OptAttrs | None = None,
        date_format: str | None = None,
        time_format: str | None = None,
        date_attrs: dict[str, str] | None = None,
        time_attrs: dict[str, str] | None = None,
    ) -> None: ...
    @override
    def decompress(self, value: Any) -> tuple[datetime.date | None, datetime.time | None]: ...

class SplitHiddenDateTimeWidget(SplitDateTimeWidget):
    template_name: str
    def __init__(
        self,
        attrs: _OptAttrs | None = None,
        date_format: str | None = None,
        time_format: str | None = None,
        date_attrs: dict[str, str] | None = None,
        time_attrs: dict[str, str] | None = None,
    ) -> None: ...

class SelectDateWidget(Widget):
    none_value: tuple[Literal[""], str]
    month_field: str
    day_field: str
    year_field: str
    template_name: str
    input_type: str
    select_widget: type[ChoiceWidget]
    date_re: Any
    years: Iterable[int | str]
    months: Mapping[int, str]
    year_none_value: tuple[Literal[""], str]
    month_none_value: tuple[Literal[""], str]
    day_none_value: tuple[Literal[""], str]
    def __init__(
        self,
        attrs: _OptAttrs | None = None,
        years: Iterable[int | str] | None = None,
        months: Mapping[int, str] | None = None,
        empty_label: str | _ListOrTuple[str] | None = None,
    ) -> None: ...
    @override
    def get_context(self, name: str, value: Any, attrs: _OptAttrs | None) -> dict[str, Any]: ...
    @override
    def format_value(self, value: Any) -> dict[str, str | int | None]: ...  # type: ignore[override]
    @override
    def id_for_label(self, id_: str) -> str: ...
    @override
    def value_from_datadict(self, data: _DataT, files: _FilesT, name: str) -> str | None | Any: ...
    @override
    def value_omitted_from_data(self, data: _DataT, files: _FilesT, name: str) -> bool: ...

__all__ = (
    "CheckboxInput",
    "CheckboxSelectMultiple",
    "ClearableFileInput",
    "ColorInput",
    "DateInput",
    "DateTimeInput",
    "EmailInput",
    "FileInput",
    "HiddenInput",
    "Media",
    "MediaDefiningClass",
    "MultiWidget",
    "MultipleHiddenInput",
    "NullBooleanSelect",
    "NumberInput",
    "PasswordInput",
    "RadioSelect",
    "Script",
    "SearchInput",
    "Select",
    "SelectDateWidget",
    "SelectMultiple",
    "SplitDateTimeWidget",
    "SplitHiddenDateTimeWidget",
    "TelInput",
    "TextInput",
    "Textarea",
    "TimeInput",
    "URLInput",
    "Widget",
)
