package db import ( "fmt" "gestion/services" "strconv" "time" "github.com/redis/go-redis/v9" ) func (d *Database) SetCommandETA(commandID, minutes int) error { key := fmt.Sprintf("command:eta:%d", commandID) now := time.Now() arrivalTime := now.Add(time.Duration(minutes) * time.Minute) eta := map[string]any{ "command_id": commandID, "total_eta_minutes": minutes, "eta_minutes": minutes, "wait_time_minutes": 0, "travel_time_minutes": minutes, "queue_position": 1, "updated_at": now.Unix(), "arrival_time": arrivalTime.Unix(), "estimated_arrival": arrivalTime.Format(time.RFC3339), } _, err := Redis.HSet(RedisCtx, key, eta).Result() if err != nil { return fmt.Errorf("erreur sauvegarde ETA: %w", err) } Redis.Expire(RedisCtx, key, 2*time.Hour) d.ScheduleETANotifications(commandID, minutes) return nil } // GetCommandETA récupère l'ETA d'une commande depuis Redis func (d *Database) GetCommandETA(commandID int) (map[string]string, error) { key := fmt.Sprintf("command:eta:%d", commandID) etaData, err := Redis.HGetAll(RedisCtx, key).Result() if err != nil { return nil, err } if len(etaData) == 0 { return nil, fmt.Errorf("aucun ETA trouvé pour la commande %d", commandID) } return etaData, nil } // CheckCommandETAExists vérifie si un ETA existe pour une commande func (d *Database) CheckCommandETAExists(commandID int) bool { key := fmt.Sprintf("command:eta:%d", commandID) exists, _ := Redis.Exists(RedisCtx, key).Result() return exists > 0 } // ScheduleETANotifications programme les notifications 5min et 3min func (d *Database) ScheduleETANotifications(commandID, etaMinutes int) error { arrivalTime := time.Now().Add(time.Duration(etaMinutes) * time.Minute) if etaMinutes > 5 { notify5min := arrivalTime.Add(-5 * time.Minute).Unix() Redis.ZAdd(RedisCtx, "notifications:scheduled", redis.Z{ Score: float64(notify5min), Member: fmt.Sprintf("%d:5min", commandID), }) } if etaMinutes > 3 { notify3min := arrivalTime.Add(-3 * time.Minute).Unix() Redis.ZAdd(RedisCtx, "notifications:scheduled", redis.Z{ Score: float64(notify3min), Member: fmt.Sprintf("%d:3min", commandID), }) } return nil } // ProcessScheduledNotifications traite les notifications à envoyer func (d *Database) ProcessScheduledNotifications() error { now := float64(time.Now().Unix()) results, err := Redis.ZRangeByScore(RedisCtx, "notifications:scheduled", &redis.ZRangeBy{ Min: "0", Max: strconv.FormatFloat(now, 'f', 0, 64), }).Result() if err != nil { return err } for _, result := range results { parts := splitNotificationKey(result) commandID, _ := strconv.Atoi(parts[0]) notifType := parts[1] d.SendETANotification(commandID, notifType) Redis.ZRem(RedisCtx, "notifications:scheduled", result) } return nil } // SendETANotification envoie une notification ETA func (d *Database) SendETANotification(commandID int, notifType string) { message := fmt.Sprintf("Votre commande #%d arrive dans %s", d.GetClientOrderID(commandID), notifType) channel := fmt.Sprintf("notifications:command:%d", commandID) Redis.Publish(RedisCtx, channel, message) } // CalculateETAForDeliveryman calcule l'ETA entre un livreur et une destination func (d *Database) CalculateETAForDeliveryman(deliveryman string, destLat, destLng float64) int { livreurLat, livreurLng, err := d.GetDeliveryPersonLocation(deliveryman) if err != nil { return services.MinETA } from := services.Coordinates{ Latitude: livreurLat, Longitude: livreurLng, } to := services.Coordinates{ Latitude: destLat, Longitude: destLng, } eta, _, err2 := services.CalculateETAWithTomTom(from, to) if err2 != nil { distance := services.CalculateDistance(from, to) eta = services.CalculateETA(distance) } return eta } // CalculateDistanceBetweenPoints calcule la distance entre deux points func (d *Database) CalculateDistanceBetweenPoints(lat1, lng1, lat2, lng2 float64) float64 { from := services.Coordinates{Latitude: lat1, Longitude: lng1} to := services.Coordinates{Latitude: lat2, Longitude: lng2} return services.CalculateDistance(from, to) } // CalculateETABetweenPoints calcule l'ETA entre deux points func (d *Database) CalculateETABetweenPoints(lat1, lng1, lat2, lng2 float64) int { distance := d.CalculateDistanceBetweenPoints(lat1, lng1, lat2, lng2) return services.CalculateETA(distance) } func (d *Database) SetCommandETAWithDetails(commandID, totalETA, queuePosition int) error { key := fmt.Sprintf("command:eta:%d", commandID) now := time.Now() arrivalTime := now.Add(time.Duration(totalETA) * time.Minute) eta := map[string]any{ "command_id": commandID, "total_eta_minutes": totalETA, "eta_minutes": totalETA, "queue_position": queuePosition, "updated_at": now.Unix(), "arrival_time": arrivalTime.Unix(), "estimated_arrival": arrivalTime.Format(time.RFC3339), } _, err := Redis.HSet(RedisCtx, key, eta).Result() if err != nil { return fmt.Errorf("erreur sauvegarde ETA: %w", err) } Redis.Expire(RedisCtx, key, 4*time.Hour) return nil }