"""A class that holds props to be passed or applied to a component."""

from __future__ import annotations

from pydantic import ValidationError

from reflex.base import Base
from reflex.utils import format
from reflex.utils.exceptions import InvalidPropValueError
from reflex.vars.object import LiteralObjectVar


class PropsBase(Base):
    """Base for a class containing props that can be serialized as a JS object."""

    def json(self) -> str:
        """Convert the object to a json-like string.

        Vars will be unwrapped so they can represent actual JS var names and functions.

        Keys will be converted to camelCase.

        Returns:
            The object as a Javascript Object literal.
        """
        return LiteralObjectVar.create(
            {format.to_camel_case(key): value for key, value in self.dict().items()}
        ).json()

    def dict(self, *args, **kwargs):
        """Convert the object to a dictionary.

        Keys will be converted to camelCase.

        Args:
            *args: Arguments to pass to the parent class.
            **kwargs: Keyword arguments to pass to the parent class.

        Returns:
            The object as a dictionary.
        """
        return {
            format.to_camel_case(key): value
            for key, value in super().dict(*args, **kwargs).items()
        }


class NoExtrasAllowedProps(Base):
    """A class that holds props to be passed or applied to a component with no extra props allowed."""

    def __init__(self, component_name=None, **kwargs):
        """Initialize the props.

        Args:
            component_name: The custom name of the component.
            kwargs: Kwargs to initialize the props.

        Raises:
            InvalidPropValueError: If invalid props are passed on instantiation.
        """
        component_name = component_name or type(self).__name__
        try:
            super().__init__(**kwargs)
        except ValidationError as e:
            invalid_fields = ", ".join([error["loc"][0] for error in e.errors()])  # pyright: ignore [reportCallIssue, reportArgumentType]
            supported_props_str = ", ".join(f'"{field}"' for field in self.get_fields())
            raise InvalidPropValueError(
                f"Invalid prop(s) {invalid_fields} for {component_name!r}. Supported props are {supported_props_str}"
            ) from None

    class Config:  # pyright: ignore [reportIncompatibleVariableOverride]
        """Pydantic config."""

        arbitrary_types_allowed = True
        use_enum_values = True
        extra = "forbid"
