from pydantic import BaseModel, Field, ValidationError, model_validator
from typing import Any, Dict
from typing import Any, Optional, TypeVar, Generic, List
from pydantic import BaseModel, Field, model_serializer

class BaseResponseWithID(BaseModel):
    """
    Mixin: 统一处理输入中的 id/_id -> id
    约束：
      - 若 id 与 _id 同时出现且值不同 -> 报错
      - 若仅 _id 出现 -> 转成 id
      - 若两者都缺失 -> 报错
      - 最终保证存在 id: str
    """
    id: str = Field(..., description="资源唯一标识ID")

    @model_validator(mode="before")
    @classmethod
    def normalize_id(cls, data: Any) -> Any:
        # 仅处理 dict-like 输入；其他情况交给 Pydantic 默认流程
        if not isinstance(data, dict):
            return data

        has_id = "id" in data
        has__id = "_id" in data

        if has_id and has__id:
            if str(data["id"]) != str(data["_id"]):
                raise ValidationError([
                    {
                        "type": "value_error",
                        "loc": ("id",),
                        "msg": "id and _id both provided but not equal",
                        "input": data.get("id"),
                    }
                ], cls)
            # 相同则优先保留 id，去掉 _id
            data = {**data}
            data.pop("_id", None)
            return data

        if has__id and not has_id:
            # 将 _id 统一映射为 id
            data = {**data}
            data["id"] = str(data["_id"])
            data.pop("_id", None)
            return data

        if not has_id and not has__id:
            raise ValidationError([
                {
                    "type": "value_error.missing",
                    "loc": ("id",),
                    "msg": "id or _id is required",
                    "input": data,
                }
            ], cls)

        # 默认返回（已有 id）
        return data


def _get_plan_node_date(node: Any) -> Any:
    if isinstance(node, dict):
        return node.get("date")
    return getattr(node, "date", None)


def trim_plan_nodes_by_boundary_dates(
    plan_nodes: Optional[List[Any]],
    start_date: Optional[Any] = None,
    end_date: Optional[Any] = None,
) -> List[Any]:
    if not plan_nodes:
        return []

    cleaned_nodes = list(plan_nodes)

    while (
        start_date is not None
        and cleaned_nodes
        and str(_get_plan_node_date(cleaned_nodes[0])) == str(start_date)
    ):
        cleaned_nodes.pop(0)

    while (
        end_date is not None
        and cleaned_nodes
        and str(_get_plan_node_date(cleaned_nodes[-1])) == str(end_date)
    ):
        cleaned_nodes.pop()

    return cleaned_nodes

class RequestApprovalMixin(BaseModel):
    """
    请求审批相关的基础模型
    """
    pass

T = TypeVar("T")


# def _build_full_response_dict(code: int, message: Optional[str], data: Any) -> dict:
#     """构建与 __orjson__ 完全一致的响应字典"""
#     # 处理 data 的序列化（与 __orjson__ 逻辑同步）
#     if data is None:
#         clean_data = {}
#     elif isinstance(data, BaseModel):
#         clean_data = data.model_dump()
#     else:
#         clean_data = data
#     return {
#         "code": code,
#         "message": message,
#         "data": clean_data
#     }

class Success(BaseModel, Generic[T]):
    code: int = 200
    message: Optional[str] = "OK"
    data: Optional[T] = None

    # def __init__(self, **kwargs):
    #     super().__init__(**kwargs)
    #     # 自动捕获完整响应结构到 push_log.result
    #     push_log = current_push_log.get()
    #     if push_log is not None:
    #         full_response = _build_full_response_dict(self.code, self.message, self.data)
    #         push_log.result = full_response
    #
class Fail(BaseModel):
    code: int = 400
    message: Optional[str] = None
    data: Optional[Any] = Field(default_factory=dict)

class PaginatedList(BaseModel, Generic[T]):
    list: List[T] = Field(default_factory=list)
    total: int = 0
    page: int = 1
    page_size: int = 20