"""Modèles de données pour la comparaison d'agenda (diff).""" from __future__ import annotations from datetime import date from enum import StrEnum from pydantic import BaseModel, ConfigDict, Field, model_validator from pronote_sync.models.agenda import Lesson, TheoreticalLesson class AgendaChangeType(StrEnum): """Type de changement dans l'agenda.""" ADDED = "added" REMOVED = "removed" MODIFIED = "modified" class AgendaChange(BaseModel): """Représente un changement entre l'agenda réel et l'agenda théorique.""" model_config = ConfigDict(frozen=True) type: AgendaChangeType = Field(..., description="Type de changement") lesson: Lesson | None = Field(None, description="Cours concerné (pour ADDED/MODIFIED)") theoretical_lesson: TheoreticalLesson | None = Field( None, description="Cours théorique concerné (pour REMOVED/MODIFIED)" ) details: str = Field(default="", description="Détails du changement") @model_validator(mode="after") def _validate_payload_consistency(self) -> AgendaChange: """Valide la cohérence entre le type de changement et le payload. Applique la matrice stricte de payload : - ``ADDED`` : ``lesson`` requis et ``theoretical_lesson`` doit être ``None``. - ``REMOVED`` : ``theoretical_lesson`` requis et ``lesson`` doit être ``None``. - ``MODIFIED`` : ``lesson`` et ``theoretical_lesson`` tous deux requis. :return: L'instance validée. :rtype: AgendaChange :raises ValueError: Si le payload ne correspond pas au type de changement. """ if self.type == AgendaChangeType.ADDED: if self.lesson is None: raise ValueError(f"lesson est requis pour le type {self.type!r}") if self.theoretical_lesson is not None: raise ValueError(f"theoretical_lesson doit être None pour le type {self.type!r}") elif self.type == AgendaChangeType.REMOVED: if self.theoretical_lesson is None: raise ValueError(f"theoretical_lesson est requis pour le type {self.type!r}") if self.lesson is not None: raise ValueError(f"lesson doit être None pour le type {self.type!r}") elif self.type == AgendaChangeType.MODIFIED: if self.lesson is None: raise ValueError(f"lesson est requis pour le type {self.type!r}") if self.theoretical_lesson is None: raise ValueError(f"theoretical_lesson est requis pour le type {self.type!r}") return self class AgendaDiff(BaseModel): """Représente les différences entre l'agenda réel et l'agenda théorique.""" model_config = ConfigDict(frozen=True) target_date: date = Field(..., description="Date cible de la comparaison") changes: tuple[AgendaChange, ...] = Field(default=(), description="Liste des changements")