from pydantic import BaseModel, Field, field_validator from typing import List, Optional, Dict, Any from datetime import datetime class OptimizerJobRequestDTO(BaseModel): """Contrato de solicitud para iniciar una optimización heurística.""" commission_ids: List[int] = Field(..., min_length=1, description="Lista de IDs de comisiones a programar") start_date: Optional[datetime] = Field(None, description="Fecha de inicio (ISO format)") end_date: Optional[datetime] = Field(None, description="Fecha de fin (ISO format)") generations: int = Field(default=80, ge=10, le=500, description="Cantidad de generaciones genéticas") population_size: int = Field(default=40, ge=10, le=200, description="Tamaño de la población de cromosomas") workers: int = Field(default=4, ge=1, le=16, description="Cantidad de hilos o workers concurrentes") @field_validator('commission_ids') @classmethod def validate_ids(cls, v): if not v or len(v) == 0: raise ValueError("Debe suministrar al menos una comisión para optimizar.") return list(set(v)) class SpringBootCommissionDTO(BaseModel): """Contrato de comisión en formato Spring Boot.""" commissionId: int subjectCode: str subjectName: str expectedAttendees: int = Field(default=30, ge=1) preferredShift: Optional[str] = "NOCHE" preferredStart: datetime preferredEnd: datetime class SpringBootClassroomDTO(BaseModel): """Contrato de aula en formato Spring Boot.""" classroomId: int roomNumber: str capacity: int = Field(default=30, ge=1) building: Optional[str] = "Edificio Central" isVirtual: bool = False class SpringBootSyncPayloadDTO(BaseModel): """Carga útil de sincronización interoperable con microservicios Spring Boot.""" requestId: str = Field(..., description="Identificador único de la petición externa") campusCode: Optional[str] = "CENTRAL" academicTerm: Optional[str] = "2026-1C" commissions: List[SpringBootCommissionDTO] = Field(..., min_length=1) classrooms: Optional[List[SpringBootClassroomDTO]] = None options: Optional[Dict[str, Any]] = None