from pydantic import BaseModel, field_validator from typing import Optional, List from datetime import datetime from enum import Enum class DependencyType(str, Enum): """Task dependency types for Gantt chart.""" FS = "FS" # Finish-to-Start (most common) SS = "SS" # Start-to-Start FF = "FF" # Finish-to-Finish SF = "SF" # Start-to-Finish (rare) class TaskDependencyCreate(BaseModel): """Schema for creating a task dependency.""" predecessor_id: str dependency_type: DependencyType = DependencyType.FS lag_days: int = 0 @field_validator('lag_days') @classmethod def validate_lag_days(cls, v): if v < -365 or v > 365: raise ValueError('lag_days must be between -365 and 365') return v class TaskDependencyUpdate(BaseModel): """Schema for updating a task dependency.""" dependency_type: Optional[DependencyType] = None lag_days: Optional[int] = None @field_validator('lag_days') @classmethod def validate_lag_days(cls, v): if v is not None and (v < -365 or v > 365): raise ValueError('lag_days must be between -365 and 365') return v class TaskInfo(BaseModel): """Brief task information for dependency response.""" id: str title: str start_date: Optional[datetime] = None due_date: Optional[datetime] = None class Config: from_attributes = True class TaskDependencyResponse(BaseModel): """Schema for task dependency response.""" id: str predecessor_id: str successor_id: str dependency_type: DependencyType lag_days: int created_at: datetime predecessor: Optional[TaskInfo] = None successor: Optional[TaskInfo] = None class Config: from_attributes = True class TaskDependencyListResponse(BaseModel): """Schema for list of task dependencies.""" dependencies: List[TaskDependencyResponse] total: int class DependencyValidationError(BaseModel): """Schema for dependency validation error details.""" error_type: str # 'circular', 'self_reference', 'duplicate', 'cross_project' message: str details: Optional[dict] = None