"""
Base DTO Classes

Provides foundational data transfer object structures.
"""

from dataclasses import dataclass, field
from datetime import datetime
from typing import Any, Generic, TypeVar, Optional, List

T = TypeVar("T")


@dataclass
class BaseDTO:
    """Base class for all DTOs."""

    def to_dict(self) -> dict[str, Any]:
        """Convert DTO to dictionary."""
        result = {}
        for key, value in self.__dict__.items():
            if isinstance(value, BaseDTO):
                result[key] = value.to_dict()
            elif isinstance(value, list):
                result[key] = [
                    item.to_dict() if isinstance(item, BaseDTO) else item
                    for item in value
                ]
            elif isinstance(value, datetime):
                result[key] = value.isoformat()
            else:
                result[key] = value
        return result

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> "BaseDTO":
        """Create DTO from dictionary."""
        return cls(**data)


@dataclass
class ResponseDTO(BaseDTO, Generic[T]):
    """Standard API response wrapper."""

    success: bool = True
    data: Optional[T] = None
    message: Optional[str] = None
    errors: Optional[List[str]] = None

    @classmethod
    def ok(cls, data: T, message: Optional[str] = None) -> "ResponseDTO[T]":
        """Create a successful response."""
        return cls(success=True, data=data, message=message)

    @classmethod
    def error(
        cls, message: str, errors: Optional[List[str]] = None
    ) -> "ResponseDTO[T]":
        """Create an error response."""
        return cls(success=False, message=message, errors=errors)


@dataclass
class ErrorDTO(BaseDTO):
    """Error information DTO."""

    code: str
    message: str
    field: Optional[str] = None
    details: Optional[dict[str, Any]] = None


@dataclass
class PaginatedDTO(BaseDTO, Generic[T]):
    """Paginated response wrapper."""

    items: List[T] = field(default_factory=list)
    total: int = 0
    page: int = 1
    page_size: int = 20
    total_pages: int = 0

    def __post_init__(self):
        if self.total > 0 and self.page_size > 0:
            self.total_pages = (self.total + self.page_size - 1) // self.page_size

    @property
    def has_next(self) -> bool:
        return self.page < self.total_pages

    @property
    def has_previous(self) -> bool:
        return self.page > 1
