using SchotzIadKmTracker.Api.Models.Entities; namespace SchotzIadKmTracker.Api.Repositories; /// /// Accès aux données des trajets et gestion des positions au sein d'une journée. /// /// La est une valeur décimale (REAL) permettant l'insertion /// sans réordonnancement systématique : ajout en fin de journée → max(Position) + 1.0, /// insertion entre deux positions P₁ et P₂ → (P₁ + P₂) / 2. Lorsque l'écart devient /// trop faible (< ), la journée est renumérotée par pas de /// 1.0 en transaction en préservant l'ordre relatif (Property 15, Exigences 11.7/11.8). /// /// /// Ce repository fournit uniquement les primitives d'accès et de calcul de position ; /// la logique métier (validation, calcul de distance, mise en cache) relève de TrajetService. /// /// public interface ITrajetRepository { /// /// Seuil de précision en deçà duquel une renumérotation de la journée est déclenchée. /// Conforme à la conception : écart < 0.001. /// const decimal SeuilRenumerotation = 0.001m; /// Retourne le trajet par identifiant, ou null s'il n'existe pas. Task GetByIdAsync(int id, CancellationToken cancellationToken = default); /// Retourne les trajets d'une journée triés par croissante. Task> GetByDateAsync(DateOnly date, CancellationToken cancellationToken = default); /// /// Résout le véhicule applicable à la date du trajet et copie sa PuissanceFiscale /// sur le trajet (dénormalisation, Exigence 10.14). Ne modifie ni VehiculeId ni /// PuissanceFiscale si aucun véhicule n'est applicable à cette date. /// Coordonné avec . /// Task AppliquerVehiculeADateAsync(Trajet trajet, CancellationToken cancellationToken = default); /// /// Calcule la position d'un trajet ajouté en fin de journée : max(Position) + 1.0 /// pour la date, ou 1.0 si la journée est vide. /// Task CalculerPositionFinDeJourneeAsync(DateOnly date, CancellationToken cancellationToken = default); /// /// Calcule la position d'un trajet inséré entre les positions /// (P₁) et (P₂) : (P₁ + P₂) / 2. /// /// Si P₁ n'est pas strictement inférieure à P₂. decimal CalculerPositionEntre(decimal positionPrecedente, decimal positionSuivante); /// /// Indique si l'écart entre deux positions adjacentes est devenu trop faible /// (< ) pour insérer une nouvelle valeur intermédiaire. /// bool NecessiteRenumerotation(decimal positionPrecedente, decimal positionSuivante); /// Ajoute un trajet (sans persister). L'appelant gère la transaction et l'appel à . Task AddAsync(Trajet trajet, CancellationToken cancellationToken = default); /// Marque un trajet existant comme modifié (sans persister). void Update(Trajet trajet); /// Supprime un trajet (sans persister). void Delete(Trajet trajet); /// Persiste les changements en attente. Task SauvegarderAsync(CancellationToken cancellationToken = default); /// /// Applique un réordonnancement manuel : met à jour uniquement la /// des trajets fournis (par identifiant) sans altérer leurs autres champs, en transaction. /// Les identifiants inconnus sont ignorés. /// Task ReordonnerAsync( IReadOnlyList<(int Id, decimal Position)> positions, CancellationToken cancellationToken = default); /// /// Renumérote les trajets d'une journée par pas de 1.0 (1.0, 2.0, 3.0, …) en préservant /// l'ordre relatif courant (tri par Position puis Id), en transaction. Retourne la liste /// renumérotée triée par Position croissante (Property 15). /// Task> RenumeroterJourneeAsync(DateOnly date, CancellationToken cancellationToken = default); }