"""
API Response Contract

Standard API response structures for consistent responses across modules.
"""

from dataclasses import dataclass, field
from typing import TypeVar, Generic, Optional, List, Any, Dict
from datetime import datetime


T = TypeVar('T')


@dataclass
class ApiResponse(Generic[T]):
    """
    Standard API response wrapper.
    
    All API endpoints should return responses in this format.
    
    Structure:
    {
        "success": true,
        "data": {...},
        "message": "...",
        "meta": {...}
    }
    """
    
    success: bool
    data: Optional[T] = None
    message: Optional[str] = None
    meta: Optional[Dict[str, Any]] = None
    
    def to_dict(self) -> Dict[str, Any]:
        """Convert to dictionary for serialization."""
        result = {"success": self.success}
        if self.data is not None:
            result["data"] = self.data
        if self.message:
            result["message"] = self.message
        if self.meta:
            result["meta"] = self.meta
        return result


@dataclass
class PaginatedApiResponse(Generic[T]):
    """
    Paginated API response for list endpoints.
    
    Structure:
    {
        "success": true,
        "data": [...],
        "meta": {
            "page": 1,
            "page_size": 20,
            "total": 100,
            "total_pages": 5
        }
    }
    """
    
    success: bool
    data: List[T]
    page: int
    page_size: int
    total: int
    
    @property
    def total_pages(self) -> int:
        """Calculate total pages."""
        if self.page_size == 0:
            return 0
        return (self.total + self.page_size - 1) // self.page_size
    
    @property
    def has_next(self) -> bool:
        """Check if there's a next page."""
        return self.page < self.total_pages
    
    @property
    def has_previous(self) -> bool:
        """Check if there's a previous page."""
        return self.page > 1
    
    def to_dict(self) -> Dict[str, Any]:
        """Convert to dictionary for serialization."""
        return {
            "success": self.success,
            "data": self.data,
            "meta": {
                "page": self.page,
                "page_size": self.page_size,
                "total": self.total,
                "total_pages": self.total_pages,
                "has_next": self.has_next,
                "has_previous": self.has_previous,
            }
        }


@dataclass
class ErrorResponse:
    """
    Standard error response.
    
    Structure:
    {
        "success": false,
        "error": {
            "code": "VALIDATION_ERROR",
            "message": "...",
            "details": [...]
        }
    }
    """
    
    code: str
    message: str
    details: Optional[List[Dict[str, Any]]] = None
    
    def to_dict(self) -> Dict[str, Any]:
        """Convert to dictionary for serialization."""
        error = {
            "code": self.code,
            "message": self.message,
        }
        if self.details:
            error["details"] = self.details
        
        return {
            "success": False,
            "error": error,
        }


# Standard error codes
class ErrorCodes:
    """Standard API error codes."""
    
    # Validation Errors (400)
    VALIDATION_ERROR = "VALIDATION_ERROR"
    INVALID_INPUT = "INVALID_INPUT"
    MISSING_FIELD = "MISSING_FIELD"
    INVALID_FORMAT = "INVALID_FORMAT"
    
    # Authentication Errors (401)
    UNAUTHORIZED = "UNAUTHORIZED"
    INVALID_TOKEN = "INVALID_TOKEN"
    TOKEN_EXPIRED = "TOKEN_EXPIRED"
    
    # Authorization Errors (403)
    FORBIDDEN = "FORBIDDEN"
    PERMISSION_DENIED = "PERMISSION_DENIED"
    TENANT_ACCESS_DENIED = "TENANT_ACCESS_DENIED"
    
    # Not Found Errors (404)
    NOT_FOUND = "NOT_FOUND"
    RESOURCE_NOT_FOUND = "RESOURCE_NOT_FOUND"
    
    # Conflict Errors (409)
    CONFLICT = "CONFLICT"
    DUPLICATE_ENTRY = "DUPLICATE_ENTRY"
    
    # Domain Errors (422)
    DOMAIN_VIOLATION = "DOMAIN_VIOLATION"
    BUSINESS_RULE_VIOLATION = "BUSINESS_RULE_VIOLATION"
    STATE_TRANSITION_ERROR = "STATE_TRANSITION_ERROR"
    
    # Rate Limit Errors (429)
    RATE_LIMITED = "RATE_LIMITED"
    
    # Server Errors (500)
    INTERNAL_ERROR = "INTERNAL_ERROR"
    SERVICE_UNAVAILABLE = "SERVICE_UNAVAILABLE"
