from __future__ import annotations

from typing import Any, Mapping, TypeVar

from pydantic import AliasChoices, BaseModel, Field, field_validator  # type: ignore
from pydantic.alias_generators import to_camel

T = TypeVar("T", bound="Schema")


class Schema(BaseModel):
    class Config:
        use_enum_values = True
        validate_default = True
        populate_by_name = True
        from_attributes = True
        arbitrary_types_allowed = True
        alias_generator = to_camel

    def update(self, **new_data: Any) -> None:
        for field, value in new_data.items():
            setattr(self, field, value)

    @classmethod
    def model_validate(
        cls: type[T],
        obj: Any,
        *,
        strict: bool | None = None,
        from_attributes: bool | None = None,
        context: dict[str, Any] | None = None,
        update: Mapping[str, Any] | None = None,
    ) -> T:
        obj_data: dict[str, Any] = {}
        if isinstance(obj, Schema):
            obj_data = obj.model_dump()
            obj_data.update(update or {})
        obj_ = super().model_validate(
            obj_data or obj,
            strict=strict,
            from_attributes=from_attributes,
            context=context,
        )
        if update:
            obj_.update(**update)
        return obj_


__all__ = ["Schema", "Field", "AliasChoices"]
