package service import ( "acc-server-manager/local/model" "acc-server-manager/local/repository" "log" "sort" "time" "github.com/gofiber/fiber/v2" ) type StateHistoryService struct { repository *repository.StateHistoryRepository } func NewStateHistoryService(repository *repository.StateHistoryRepository) *StateHistoryService { return &StateHistoryService{ repository: repository, } } // GetAll // Gets All rows from StateHistory table. // // Args: // context.Context: Application context // Returns: // string: Application version func (s *StateHistoryService) GetAll(ctx *fiber.Ctx, filter *model.StateHistoryFilter) (*[]model.StateHistory, error) { result, err := s.repository.GetAll(ctx.UserContext(), filter) if err != nil { log.Printf("Error getting state history: %v", err) return nil, err } return result, nil } func (s *StateHistoryService) Insert(ctx *fiber.Ctx, model *model.StateHistory) error { if err := s.repository.Insert(ctx.UserContext(), model); err != nil { log.Printf("Error inserting state history: %v", err) return err } return nil } func (s *StateHistoryService) GetStatistics(ctx *fiber.Ctx, filter *model.StateHistoryFilter) (*model.StateHistoryStats, error) { // Get all state history entries based on filter entries, err := s.repository.GetAll(ctx.UserContext(), filter) if err != nil { log.Printf("Error getting state history for statistics: %v", err) return nil, err } stats := &model.StateHistoryStats{ PlayerCountOverTime: make([]model.PlayerCountPoint, 0), SessionTypes: make([]model.SessionCount, 0), DailyActivity: make([]model.DailyActivity, 0), RecentSessions: make([]model.RecentSession, 0), } if len(*entries) == 0 { return stats, nil } // Maps to track unique sessions and their details sessionMap := make(map[uint]*struct { StartTime time.Time EndTime time.Time Session string Track string MaxPlayers int }) // Maps for aggregating statistics dailySessionCount := make(map[string]int) sessionTypeCount := make(map[string]int) totalPlayers := 0 peakPlayers := 0 // Process each state history entry for _, entry := range *entries { // Track player count over time stats.PlayerCountOverTime = append(stats.PlayerCountOverTime, model.PlayerCountPoint{ Timestamp: entry.DateCreated, Count: entry.PlayerCount, }) // Update peak players if entry.PlayerCount > peakPlayers { peakPlayers = entry.PlayerCount } totalPlayers += entry.PlayerCount // Process session information using SessionID if _, exists := sessionMap[entry.SessionID]; !exists { sessionMap[entry.SessionID] = &struct { StartTime time.Time EndTime time.Time Session string Track string MaxPlayers int }{ StartTime: entry.DateCreated, Session: entry.Session, Track: entry.Track, MaxPlayers: entry.PlayerCount, } // Count session types sessionTypeCount[entry.Session]++ // Count daily sessions dateStr := entry.DateCreated.Format("2006-01-02") dailySessionCount[dateStr]++ } else { session := sessionMap[entry.SessionID] session.EndTime = entry.DateCreated if entry.PlayerCount > session.MaxPlayers { session.MaxPlayers = entry.PlayerCount } } } // Calculate statistics stats.PeakPlayers = peakPlayers stats.TotalSessions = len(sessionMap) if len(*entries) > 0 { stats.AveragePlayers = float64(totalPlayers) / float64(len(*entries)) } // Process session types for sessionType, count := range sessionTypeCount { stats.SessionTypes = append(stats.SessionTypes, model.SessionCount{ Name: sessionType, Count: count, }) } // Process daily activity for dateStr, count := range dailySessionCount { date, _ := time.Parse("2006-01-02", dateStr) stats.DailyActivity = append(stats.DailyActivity, model.DailyActivity{ Date: date, SessionsCount: count, }) } // Calculate total playtime and prepare recent sessions var recentSessions []model.RecentSession totalPlaytime := 0 for sessionID, session := range sessionMap { if !session.EndTime.IsZero() { duration := int(session.EndTime.Sub(session.StartTime).Minutes()) totalPlaytime += duration recentSessions = append(recentSessions, model.RecentSession{ ID: sessionID, Date: session.StartTime, Type: session.Session, Track: session.Track, Duration: duration, Players: session.MaxPlayers, }) } } stats.TotalPlaytime = totalPlaytime // Sort recent sessions by date (newest first) and limit to last 10 sort.Slice(recentSessions, func(i, j int) bool { return recentSessions[i].Date.After(recentSessions[j].Date) }) if len(recentSessions) > 10 { recentSessions = recentSessions[:10] } stats.RecentSessions = recentSessions // Sort daily activity by date sort.Slice(stats.DailyActivity, func(i, j int) bool { return stats.DailyActivity[i].Date.Before(stats.DailyActivity[j].Date) }) // Sort player count over time by timestamp sort.Slice(stats.PlayerCountOverTime, func(i, j int) bool { return stats.PlayerCountOverTime[i].Timestamp.Before(stats.PlayerCountOverTime[j].Timestamp) }) return stats, nil }