from pydantic import Field, BaseModel,field_validator,model_validator
from fastapi import HTTPException
from typing import List, Optional, Literal
from ..common.validators import DateStr
from ..common.base import BaseResponseWithID, trim_plan_nodes_by_boundary_dates

class PlanNode(BaseModel):
    date: DateStr = Field(..., description="计划节点时间", examples=["2024-01-01"])
    quantity: float = Field(..., description="计划完成量", examples=[100.0])
    is_audit: Optional[bool] = Field(False, description="是否已审核", examples=[False])

    @field_validator("quantity")
    def validate_quantity(cls, v):
        """验证计划到场人数必须为非负数"""
        if v < 0:
            raise HTTPException(status_code=400, detail='计划节点人数不能小于0')
        return v

class PowerResponse(BaseResponseWithID):
    """
    力能模型
    """
    code: Optional[str] = Field(
        "personnel",
        description="力能类型(人员模块拓展为力能模块，可以在本字段保存人员/机具等编码)",
        examples=["personnel"],
    )
    project_id: str = Field(..., description="所属项目", examples=["project123"])
    contract_id: Optional[str] = Field(
        None,
        description="所属合同(目前前端页面显示没有按这个字段，仅通过脚本绑定了epc合同，用于接口数据推送。后续行为待讨论)",
        examples=["contract456"],
    )
    show_name: str = Field("", description="展示名称", examples=["施工班组A"])
    status: Optional[int] = Field(None, description="人员状态", examples=[0])
    plan_attendance: int = Field(
        0,
        description="计划出勤人数(暂时定为最后一次报明细时的计划出勤人数)",
        examples=[10],
    )
    actual_daily_attendance: int = Field(0, description="实际日均出勤", examples=[8])
    attendance_rate: float = Field(0.0, description="出勤率", examples=[0.8])
    statistic_date: Optional[DateStr] = Field(
        None, description="统计节点", examples=["2024-05-31"]
    )
    plan_exit_date: Optional[DateStr] = Field(
        None, description="计划退场时间", examples=["2024-06-30"]
    )
    actual_exit_date: Optional[DateStr] = Field(
        None, description="实际退场时间", examples=["2024-07-05"]
    )
    plan_node: List[PlanNode] = Field(default_factory=list, description="计划节点列表")
    plan_start_date: Optional[DateStr] = Field(
        None, description="计划首批到场时间", examples=["2024-05-01"]
    )
    plan_start_quantity: int = Field(0, description="计划首批到场人数", examples=[5], ge=0)
    actual_start_date: Optional[DateStr] = Field(
        None, description="实际首批到场时间", examples=["2024-05-02"]
    )
    actual_start_quantity: Optional[int] = Field(
        None, description="实际首批到场人数", examples=[4]
    )

    @model_validator(mode='after')
    def clean_response_plan_nodes(self):
        self.plan_node = trim_plan_nodes_by_boundary_dates(
            self.plan_node,
            start_date=self.plan_start_date,
            end_date=self.plan_exit_date,
        )
        return self

class PowerCreate(BaseModel):
    """
    创建力能
    POWER_BASE_INFO = "personnel.base_info"
    """
    project_id: str = Field(..., description="所属项目ID", examples=["project123"])
    contract_id: Optional[str] = Field(
        None, description="所属合同ID", examples=["contract456"]
    )
    #show_name: str = Field(..., description="展示名称", examples=["施工班组A"])
    code: Optional[str] = Field(
        "personnel",
        description="力能类型(人员模块拓展为力能模块，可以在本字段保存人员/机具等编码)",
        examples=["personnel"],
    )

class PowerUpdate(BaseModel):
    """
    更新力能
    POWER_BASE_INFO = "personnel.base_info"
    """
    id: str = Field(..., description="力能ID")
    contract_id: Optional[str] = Field(
        None, description="所属合同ID", examples=["contract456"]
    )
    #show_name: Optional[str] = Field(None, description="展示名称", examples=["施工班组A"])

class PowerPlanUpdate(BaseModel):
    """
    力能计划更新模型
    POWER_PLAN = "personnel.plan"
    
    业务逻辑说明：
    - API要求计划节点时间必须晚于计划首批到场时间（不能等于）
    - 自动清理脏数据：如果 plan_node 有2个或以上节点，删除边界节点
    """
    id: str = Field(..., description="力能ID")
    plan_start_date: str = Field(..., description="计划首批到场时间")
    plan_start_quantity: int = Field(..., description="计划首批到场人数")
    plan_exit_date: DateStr = Field(
        ..., description="计划退场时间", examples=["2024-06-30"]
    )
    plan_node: List[PlanNode] = Field(default_factory=list, description="计划节点列表")

    @field_validator("plan_start_quantity")
    def validate_quantity(cls, v):
        """验证计划首批到场人数必须为非负数"""
        if v < 0:
            raise HTTPException(status_code=400, detail='计划首批进场人数必须大于等于0')
        return v
    
    @model_validator(mode='after')
    def clean_plan_nodes(self):
        """
        清理计划节点列表中的边界节点
        
        如果 plan_node 有2个或以上节点，删除：
        - 开头节点：date 等于 plan_start_date
        - 结尾节点：date 等于 plan_exit_date
        
        这避免了API报错“计划节点时间必须晚于计划首批到场时间”
        """
        if not self.plan_node or len(self.plan_node) < 2:
            return self
        
        cleaned_nodes = list(self.plan_node)
        
        # 删除开头的边界节点
        if (self.plan_start_date and 
            cleaned_nodes and 
            cleaned_nodes[0].date == self.plan_start_date):
            cleaned_nodes.pop(0)
        
        # 删除结尾的边界节点
        if (self.plan_exit_date and 
            cleaned_nodes and 
            cleaned_nodes[-1].date == self.plan_exit_date):
            cleaned_nodes.pop()
        
        self.plan_node = cleaned_nodes
        return self