package db import ( "encoding/json" "fmt" "gestion/models" "log" "math" ) // FindLeastLoadedDeliveryman trouve le livreur avec le moins de commandes ET qui peut accepter func (d *Database) FindLeastLoadedDeliveryman() (string, error) { keys, err := Redis.Keys(RedisCtx, "delivery:status:*").Result() if err != nil || len(keys) == 0 { return "", fmt.Errorf("aucun livreur trouvé") } var leastLoaded string minQueueSize := int64(MAX_COMMANDS_PER_DELIVERYMAN + 1) for _, key := range keys { username := key[len("delivery:status:"):] data, err := Redis.Get(RedisCtx, key).Result() if err != nil { continue } var status models.DeliveryPersonStatus json.Unmarshal([]byte(data), &status) if status.Status == "offline" { continue } // ✅ NOUVEAU: Vérifier si le livreur peut accepter des commandes if !d.CanDeliverymanAcceptCommands(username) { log.Printf("⏭️ [LEAST_LOADED] Skip %s: ne peut pas accepter", username) continue } queueKey := fmt.Sprintf("queue:deliveryman:%s", username) queueSize, _ := Redis.ZCard(RedisCtx, queueKey).Result() // Priorité aux livreurs disponibles (bonus de -1000) effectiveQueueSize := queueSize if status.Status == "available" { effectiveQueueSize -= 1000 } if effectiveQueueSize < minQueueSize { minQueueSize = effectiveQueueSize leastLoaded = username } } if leastLoaded == "" { return "", fmt.Errorf("aucun livreur disponible") } queueKey := fmt.Sprintf("queue:deliveryman:%s", leastLoaded) actualQueueSize, _ := Redis.ZCard(RedisCtx, queueKey).Result() log.Printf("🎯 [LEAST_LOADED] %s sélectionné (%d/10 commandes)", leastLoaded, actualQueueSize) return leastLoaded, nil } // FindAvailableOrLeastLoadedDeliveryman trouve un livreur disponible ou le moins chargé func (d *Database) FindAvailableOrLeastLoadedDeliveryman() (string, string, int, error) { keys, err := Redis.Keys(RedisCtx, "delivery:status:*").Result() if err != nil || len(keys) == 0 { return "", "", 0, fmt.Errorf("aucun livreur trouvé") } var bestDeliveryman string var bestStatus string bestQueueSize := int64(MAX_COMMANDS_PER_DELIVERYMAN + 1) for _, key := range keys { username := key[len("delivery:status:"):] data, err := Redis.Get(RedisCtx, key).Result() if err != nil { continue } var status models.DeliveryPersonStatus json.Unmarshal([]byte(data), &status) if status.Status == "offline" { continue } if !d.CanDeliverymanAcceptCommands(username) { continue } queueKey := fmt.Sprintf("queue:deliveryman:%s", username) queueSize, _ := Redis.ZCard(RedisCtx, queueKey).Result() if status.Status == "available" && queueSize == 0 { return username, "available", 0, nil } if queueSize < bestQueueSize { bestQueueSize = queueSize bestDeliveryman = username bestStatus = status.Status } } if bestDeliveryman == "" { return "", "", 0, fmt.Errorf("tous les livreurs sont au maximum de leur capacité") } return bestDeliveryman, bestStatus, int(bestQueueSize), nil } // GetLeastLoadedDeliverymanForced retourne le livreur avec le moins de commandes (SANS limite) func (d *Database) GetLeastLoadedDeliverymanForced() (string, int64, error) { activeUsernames, err := d.GetAllActiveDeliverymenUsernames() if err != nil || len(activeUsernames) == 0 { return "", 0, fmt.Errorf("aucun livreur actif") } var leastLoaded string var minQueueSize int64 = math.MaxInt64 for _, username := range activeUsernames { queueKey := fmt.Sprintf("queue:deliveryman:%s", username) queueSize, _ := Redis.ZCard(RedisCtx, queueKey).Result() if queueSize < minQueueSize { minQueueSize = queueSize leastLoaded = username } } return leastLoaded, minQueueSize, nil } // AreAllDeliverymenAtCapacity vérifie si tous les livreurs ont atteint leur capacité max func (d *Database) AreAllDeliverymenAtCapacity() (bool, int, error) { activeUsernames, err := d.GetAllActiveDeliverymenUsernames() if err != nil || len(activeUsernames) == 0 { return false, 0, fmt.Errorf("aucun livreur actif") } if len(activeUsernames) == 1 { return false, 1, nil } atCapacityCount := 0 for _, username := range activeUsernames { if !d.CanDeliverymanAcceptCommands(username) { atCapacityCount++ } } allAtCapacity := atCapacityCount == len(activeUsernames) if allAtCapacity { log.Printf("🔴 [CAPACITY] TOUS les livreurs sont à capacité maximale (%d/%d)", atCapacityCount, len(activeUsernames)) } return allAtCapacity, len(activeUsernames), nil }