"""
统一响应模型

定义标准化的 API 响应格式。
所有 API 响应都应使用 ResponseModel。
"""

from typing import Generic, TypeVar, Optional, Dict, Any, List
from datetime import datetime
from pydantic import BaseModel, Field, ConfigDict, field_validator
import uuid

from src.utils.errors import ErrorCode

T = TypeVar("T")


class ResponseMeta(BaseModel):
    """响应元数据"""
    request_id: str = Field(default_factory=lambda: str(uuid.uuid4()))
    timestamp: str = Field(default_factory=lambda: datetime.now().isoformat())
    api_version: str = "v1"
    # 分页信息（可选）
    page: Optional[int] = None
    page_size: Optional[int] = None
    total: Optional[int] = None
    total_pages: Optional[int] = None


class ResponseModel(BaseModel, Generic[T]):
    """
    统一响应模型

    所有 API 响应都应使用此格式包装。

    Attributes:
        code: 业务状态码 (ErrorCode.SUCCESS=成功，4xxx=客户端错误，5xxx=服务端错误)
        message: 人类可读的消息
        data: 响应数据
        meta: 响应元数据
    """
    code: str = ErrorCode.SUCCESS.value
    message: str = "success"
    data: Optional[T] = None
    meta: ResponseMeta = Field(default_factory=ResponseMeta)

    model_config = ConfigDict(
        use_enum_values=True,
        json_schema_extra={
            "example": {
                "code": "0000",
                "message": "success",
                "data": {},
                "meta": {
                    "request_id": "uuid",
                    "timestamp": "2024-01-01T00:00:00",
                    "api_version": "v1"
                }
            }
        }
    )

    @field_validator("code", mode="before")
    @classmethod
    def _normalize_code(cls, value: Any) -> str:
        if isinstance(value, ErrorCode):
            return value.value
        return str(value)

    @property
    def metadata(self) -> Dict[str, Any]:
        return self.meta.model_dump() if self.meta is not None else {}


class ErrorResponse(BaseModel):
    """错误响应模型"""
    code: ErrorCode
    message: str
    details: Optional[Dict[str, Any]] = None

    model_config = ConfigDict(use_enum_values=True)


class PaginationParams(BaseModel):
    """分页参数"""
    page: int = Field(default=1, ge=1, description="页码（从 1 开始）")
    page_size: int = Field(default=20, ge=1, le=100, description="每页数量")
    sort: Optional[str] = Field(None, description="排序字段，格式：field:asc 或 field:desc")
    filter: Optional[str] = Field(None, description="过滤条件，JSON 格式")

    @property
    def offset(self) -> int:
        """计算数据库偏移量"""
        return (self.page - 1) * self.page_size

    def get_offset(self) -> int:
        """获取分页偏移量"""
        return self.offset

    def get_limit(self) -> int:
        """获取分页限制数量"""
        return self.page_size

    def get_sort_params(self) -> tuple[Optional[str], Optional[str]]:
        """解析排序参数

        Returns:
            tuple: (字段名，排序方向) 或 (None, None)
        """
        if not self.sort:
            return None, None

        parts = self.sort.split(":")
        if len(parts) != 2:
            return None, None

        field, direction = parts
        direction = direction.lower()

        if direction not in ["asc", "desc"]:
            return None, None

        return field, direction


class PaginationMetadata(BaseModel):
    """分页元数据"""
    page: int = Field(default=1, description="页码（从 1 开始）")
    page_size: int = Field(default=20, description="每页数量")
    total: int = Field(default=0, description="总记录数")
    total_pages: int = Field(default=0, description="总页数")

    @classmethod
    def create(
        cls,
        page: int,
        page_size: int,
        total: int
    ) -> "PaginationMetadata":
        """创建分页元数据

        Args:
            page: 当前页码
            page_size: 每页数量
            total: 总数量

        Returns:
            PaginationMetadata 实例
        """
        total_pages = (total + page_size - 1) // page_size if page_size > 0 else 0
        return cls(
            page=page,
            page_size=page_size,
            total=total,
            total_pages=total_pages
        )


class PaginatedResponse(ResponseModel[T], Generic[T]):
    """
    分页响应模型

    自动包含分页元数据。

    响应格式:
    {
        "code": "0000",
        "message": "success",
        "data": {
            "items": [...],
            "pagination": {"page": 1, "page_size": 20, "total": 100, "total_pages": 5}
        },
        "meta": {
            "request_id": "uuid",
            "timestamp": "2024-01-15T10:30:00Z",
            "api_version": "v1",
            "page": 1,
            "page_size": 20,
            "total": 100,
            "total_pages": 5
        }
    }
    """

    @classmethod
    def create(
        cls,
        items: List[T],
        page: int,
        page_size: int,
        total: int,
        message: str = "success",
        code: ErrorCode = ErrorCode.SUCCESS
    ) -> "PaginatedResponse[T]":
        """创建分页响应

        Args:
            items: 数据项列表
            page: 当前页码
            page_size: 每页数量
            total: 总数量
            message: 消息
            code: 业务状态码

        Returns:
            分页响应字典
        """
        total_pages = (total + page_size - 1) // page_size if page_size > 0 else 0

        # 创建分页元数据
        pagination = {
            "page": page,
            "page_size": page_size,
            "total": total,
            "total_pages": total_pages
        }

        # data 包含 items 和 pagination
        data = {
            "items": items,
            "pagination": pagination
        }

        meta = ResponseMeta(
            page=page,
            page_size=page_size,
            total=total,
            total_pages=total_pages
        )

        return cls(
            code=code,
            message=message,
            data=data,
            meta=meta
        )


def create_response(
    data: Optional[T] = None,
    message: str = "success",
    code: ErrorCode = ErrorCode.SUCCESS,
    **kwargs
) -> Dict[str, Any]:
    """
    创建标准响应字典

    Args:
        data: 响应数据
        message: 消息
        code: 业务状态码
        **kwargs: 额外的元数据字段

    Returns:
        响应字典
    """
    meta = {
        "request_id": str(uuid.uuid4()),
        "timestamp": datetime.now().isoformat(),
        "api_version": "v1"
    }
    meta.update(kwargs)

    return {
        "code": code,
        "message": message,
        "data": data,
        "meta": meta
    }


def create_error_response(
    message: str,
    code: ErrorCode = ErrorCode.UNKNOWN_ERROR,
    details: Optional[Dict[str, Any]] = None,
    **kwargs
) -> Dict[str, Any]:
    """
    创建错误响应字典

    Args:
        message: 错误消息
        code: 错误状态码
        details: 详细错误信息
        **kwargs: 额外的元数据字段

    Returns:
        错误响应字典

    Note:
        建议使用 src.utils.errors 中的 ErrorCode 枚举和 AppException 类
    """
    response = create_response(
        data=None,
        message=message,
        code=code,
        **kwargs
    )

    if details:
        response["details"] = details

    return response

