"""Base Pydantic schemas with common configuration."""

from datetime import datetime
from typing import Any

from pydantic import BaseModel, ConfigDict


def to_camel(string: str) -> str:
    """Convert snake_case to camelCase."""
    components = string.split("_")
    return components[0] + "".join(x.title() for x in components[1:])


class BaseSchema(BaseModel):
    """
    Base schema with common configuration.

    Features:
    - camelCase serialization for API responses
    - from_attributes=True for ORM model conversion
    - Populate by name for accepting both camelCase and snake_case
    """

    model_config = ConfigDict(
        from_attributes=True,
        populate_by_name=True,
        alias_generator=to_camel,
    )


class BaseRequest(BaseSchema):
    """Base schema for request DTOs."""

    pass


class BaseResponse(BaseSchema):
    """Base schema for response DTOs."""

    pass


class TimestampMixin(BaseModel):
    """Mixin for models with timestamps."""

    created_at: datetime
    updated_at: datetime


class ResponseWithTimestamps(BaseResponse, TimestampMixin):
    """Base response schema with timestamps."""

    pass


class ErrorDetail(BaseSchema):
    """
    Standard error detail schema.

    All error responses from the library follow this structure.

    Attributes:
        code: Machine-readable error code (e.g., "AUTH_ERROR", "VALIDATION_ERROR")
        message: Human-readable error message
        details: Additional error details (optional, can include fields, constraints, etc.)

    Examples:
        Simple error:
        {
            "error": {
                "code": "USER_NOT_FOUND",
                "message": "User not found"
            }
        }

        Error with details:
        {
            "error": {
                "code": "QUOTA_EXCEEDED",
                "message": "Quota exceeded for 'api_calls': 1050/1000 (monthly)",
                "details": {
                    "feature_code": "api_calls",
                    "limit": 1000,
                    "used": 1050,
                    "period": "monthly",
                    "remaining": -50
                }
            }
        }

        Validation error:
        {
            "error": {
                "code": "VALIDATION_ERROR",
                "message": "Validation failed for 2 field(s)",
                "details": {
                    "errors": [
                        {
                            "field": "email",
                            "message": "Field 'email' is required",
                            "type": "missing"
                        },
                        {
                            "field": "age",
                            "message": "Invalid type for 'age': value is not a valid integer",
                            "type": "type_error"
                        }
                    ]
                }
            }
        }
    """

    code: str
    message: str
    details: dict[str, Any] | None = None


class ErrorResponse(BaseSchema):
    """
    Standard error response schema.

    All errors from the library are wrapped in this structure.
    """

    error: ErrorDetail
