package service import ( "context" "fmt" "time" "bugulma/backend/internal/domain" ) type AdminService struct { orgService *OrganizationService userService *UserService verificationService *VerificationService i18nService *I18nService } func NewAdminService( orgService *OrganizationService, userService *UserService, verificationService *VerificationService, i18nService *I18nService, ) *AdminService { return &AdminService{ orgService: orgService, userService: userService, verificationService: verificationService, i18nService: i18nService, } } // DashboardStats represents dashboard statistics type DashboardStats struct { TotalOrganizations int64 `json:"totalOrganizations"` VerifiedOrganizations int64 `json:"verifiedOrganizations"` ActiveConnections int64 `json:"activeConnections"` NewThisMonth int64 `json:"newThisMonth"` PendingVerifications int64 `json:"pendingVerifications"` PendingTranslations int64 `json:"pendingTranslations"` SystemAlerts int64 `json:"systemAlerts"` } // GetDashboardStats retrieves dashboard statistics func (s *AdminService) GetDashboardStats(ctx context.Context) (*DashboardStats, error) { // Get all organizations allOrgs, err := s.orgService.GetAll(ctx) if err != nil { return nil, fmt.Errorf("failed to get organizations: %w", err) } stats := &DashboardStats{ TotalOrganizations: int64(len(allOrgs)), } // Count verified organizations verifiedCount := int64(0) now := time.Now() monthStart := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()) newThisMonth := int64(0) for _, org := range allOrgs { if org.Verified { verifiedCount++ } if org.CreatedAt.After(monthStart) { newThisMonth++ } } stats.VerifiedOrganizations = verifiedCount stats.NewThisMonth = newThisMonth // Get pending verifications verificationQueue, err := s.verificationService.GetVerificationQueue(ctx, VerificationQueueFilters{ Status: func() *domain.VerificationStatus { status := domain.VerificationPending return &status }(), }) if err == nil { stats.PendingVerifications = int64(len(verificationQueue)) } // Get pending translations (simplified - would need more detailed i18n stats) translationStats, err := s.i18nService.GetTranslationStats(ctx, "") if err == nil { // Calculate missing translations if totalKeys, ok := translationStats["total_unique_keys"].(int64); ok { if translatedCounts, ok := translationStats["translated_counts"].(map[string]int64); ok { // Count missing for each locale var totalMissing int64 for locale, count := range translatedCounts { if locale != DefaultLocale { missing := totalKeys - count if missing > 0 { totalMissing += missing } } } stats.PendingTranslations = totalMissing } } } // Active connections would come from matching/proposal service // For now, set to 0 stats.ActiveConnections = 0 stats.SystemAlerts = 0 return stats, nil } // OrganizationStats represents organization statistics type OrganizationStats struct { Total int64 `json:"total"` Verified int64 `json:"verified"` Pending int64 `json:"pending"` Unverified int64 `json:"unverified"` NewThisMonth int64 `json:"newThisMonth"` BySector map[string]int64 `json:"bySector"` BySubtype map[string]int64 `json:"bySubtype"` VerificationRate float64 `json:"verificationRate"` } // GetOrganizationStats retrieves organization statistics func (s *AdminService) GetOrganizationStats(ctx context.Context, filters map[string]interface{}) (*OrganizationStats, error) { allOrgs, err := s.orgService.GetAll(ctx) if err != nil { return nil, fmt.Errorf("failed to get organizations: %w", err) } stats := &OrganizationStats{ Total: int64(len(allOrgs)), BySector: make(map[string]int64), BySubtype: make(map[string]int64), } now := time.Now() monthStart := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()) for _, org := range allOrgs { if org.Verified { stats.Verified++ } else { stats.Unverified++ } if org.CreatedAt.After(monthStart) { stats.NewThisMonth++ } stats.BySector[string(org.Sector)]++ stats.BySubtype[string(org.Subtype)]++ } // Get pending verifications verificationQueue, err := s.verificationService.GetVerificationQueue(ctx, VerificationQueueFilters{}) if err == nil { stats.Pending = int64(len(verificationQueue)) } if stats.Total > 0 { stats.VerificationRate = float64(stats.Verified) / float64(stats.Total) * 100 } return stats, nil } // UserActivityStats represents user activity statistics type UserActivityStats struct { TotalUsers int64 `json:"totalUsers"` ActiveUsers int64 `json:"activeUsers"` InactiveUsers int64 `json:"inactiveUsers"` NewThisMonth int64 `json:"newThisMonth"` ByRole map[string]int64 `json:"byRole"` LastLoginStats map[string]int64 `json:"lastLoginStats"` // last_7_days, last_30_days, never } // GetUserActivityStats retrieves user activity statistics func (s *AdminService) GetUserActivityStats(ctx context.Context, filters map[string]interface{}) (*UserActivityStats, error) { userStats, err := s.userService.GetUserStats(ctx) if err != nil { return nil, fmt.Errorf("failed to get user stats: %w", err) } stats := &UserActivityStats{ ByRole: make(map[string]int64), LastLoginStats: make(map[string]int64), } if total, ok := userStats["total"].(int64); ok { stats.TotalUsers = total } if active, ok := userStats["active"].(int); ok { stats.ActiveUsers = int64(active) } if inactive, ok := userStats["inactive"].(int); ok { stats.InactiveUsers = int64(inactive) } if newThisMonth, ok := userStats["new_this_month"].(int); ok { stats.NewThisMonth = int64(newThisMonth) } if byRole, ok := userStats["by_role"].(map[string]int64); ok { stats.ByRole = byRole } return stats, nil } // MatchingStats represents matching statistics type MatchingStats struct { TotalMatches int64 `json:"totalMatches"` ActiveMatches int64 `json:"activeMatches"` SuccessfulMatches int64 `json:"successfulMatches"` MatchRate float64 `json:"matchRate"` } // GetMatchingStats retrieves matching statistics func (s *AdminService) GetMatchingStats(ctx context.Context, filters map[string]interface{}) (*MatchingStats, error) { // TODO: Implement when matching service is available stats := &MatchingStats{ TotalMatches: 0, ActiveMatches: 0, SuccessfulMatches: 0, MatchRate: 0, } return stats, nil } // SystemHealth represents system health metrics type SystemHealth struct { Status string `json:"status"` // healthy, degraded, down Database string `json:"database"` Cache string `json:"cache"` ExternalServices map[string]string `json:"externalServices"` Uptime int64 `json:"uptime"` // seconds ResponseTime int64 `json:"responseTime"` // milliseconds ErrorRate float64 `json:"errorRate"` ActiveConnections int64 `json:"activeConnections"` } // GetSystemHealth retrieves system health metrics func (s *AdminService) GetSystemHealth(ctx context.Context) (*SystemHealth, error) { health := &SystemHealth{ Status: "healthy", Database: "connected", Cache: "connected", ExternalServices: make(map[string]string), Uptime: 0, ResponseTime: 0, ErrorRate: 0, } // TODO: Implement actual health checks // - Database connectivity // - Cache connectivity // - External service status // - System metrics return health, nil }