"""Generic Graph API response models for pagination and error handling."""

from typing import Generic, TypeVar

from pydantic import BaseModel, ConfigDict, Field


T = TypeVar("T")


class GraphErrorDetail(BaseModel):
    """Nested error details from Graph API error responses.

    Graph API errors can contain nested details for complex error scenarios.
    The details field is self-referential to support arbitrary nesting depth.

    Attributes:
        code: Error code string (e.g., "BadRequest", "ResourceNotFound").
        message: Human-readable error message.
        target: The target of the error, typically the field or parameter that caused it.
        details: Nested error details for additional context.
    """

    model_config = ConfigDict(extra="forbid", populate_by_name=True)

    code: str
    message: str
    target: str | None = None
    details: list["GraphErrorDetail"] | None = None


class GraphErrorResponse(BaseModel):
    """Graph API error response wrapper.

    Standard error response format returned by Microsoft Graph API
    when a request fails. Contains a single error object with details.

    Attributes:
        error: The error detail object containing code, message, and optional nested details.
    """

    model_config = ConfigDict(extra="forbid", populate_by_name=True)

    error: GraphErrorDetail


class GraphListResponse(BaseModel, Generic[T]):
    """Generic wrapper for paginated Graph API list responses.

    Microsoft Graph API returns list results in a consistent format with
    OData annotations for context, count, and pagination. This generic
    model can wrap any item type T for type-safe parsing.

    Type Parameters:
        T: The type of items in the value list (e.g., UserConfiguration).

    Attributes:
        odata_context: OData context URL describing the response metadata.
        odata_count: Total count of items when requested with $count=true.
        odata_next_link: URL to fetch the next page of results.
        value: List of items of type T.
    """

    model_config = ConfigDict(extra="forbid", populate_by_name=True)

    odata_context: str | None = Field(alias="@odata.context", default=None)
    odata_count: int | None = Field(alias="@odata.count", default=None)
    odata_next_link: str | None = Field(alias="@odata.nextLink", default=None)
    value: list[T]
