using GreenHome.Application; using Microsoft.EntityFrameworkCore; namespace GreenHome.Infrastructure; public sealed class MonthlyReportService : IMonthlyReportService { private readonly GreenHomeDbContext _context; public MonthlyReportService(GreenHomeDbContext context) { _context = context; } public async Task GetMonthlyReportAsync( int deviceId, int year, int month, CancellationToken cancellationToken) { var device = await _context.Devices .FirstOrDefaultAsync(d => d.Id == deviceId, cancellationToken); if (device == null) { throw new InvalidOperationException($"دستگاه با شناسه {deviceId} یافت نشد"); } // Get alert logs for the month var alertLogs = await _context.AlertLogs .Where(al => al.DeviceId == deviceId && al.SentAt.Year == year && al.SentAt.Month == month) .ToListAsync(cancellationToken); var totalAlerts = alertLogs.Count; var smsAlerts = alertLogs.Count(al => al.NotificationType == Domain.AlertNotificationType.SMS); var callAlerts = alertLogs.Count(al => al.NotificationType == Domain.AlertNotificationType.Call); var successfulAlerts = alertLogs.Count(al => al.Status == Domain.AlertStatus.Success); var failedAlerts = alertLogs.Count(al => al.Status == Domain.AlertStatus.Failed); var powerOutageAlerts = alertLogs.Count(al => al.AlertType == Domain.AlertType.PowerOutage); // Get telemetry statistics var telemetryData = await _context.TelemetryRecords .Where(t => t.DeviceId == deviceId && t.PersianYear == year && t.PersianMonth == month) .ToListAsync(cancellationToken); var totalTelemetryRecords = telemetryData.Count; var avgTemp = telemetryData.Any() ? telemetryData.Average(t => t.TemperatureC) : 0; var minTemp = telemetryData.Any() ? telemetryData.Min(t => t.TemperatureC) : 0; var maxTemp = telemetryData.Any() ? telemetryData.Max(t => t.TemperatureC) : 0; var avgHumidity = telemetryData.Any() ? telemetryData.Average(t => t.HumidityPercent) : 0; var minHumidity = telemetryData.Any() ? telemetryData.Min(t => t.HumidityPercent) : 0; var maxHumidity = telemetryData.Any() ? telemetryData.Max(t => t.HumidityPercent) : 0; var avgLux = telemetryData.Any() ? telemetryData.Average(t => t.Lux) : 0; var avgGas = telemetryData.Any() ? (int)telemetryData.Average(t => t.GasPPM) : 0; var maxGas = telemetryData.Any() ? telemetryData.Max(t => t.GasPPM) : 0; // Get user activity var userReportsCount = await _context.UserDailyReports .CountAsync(r => r.DeviceId == deviceId && r.PersianYear == year && r.PersianMonth == month, cancellationToken); var checklistCompletionsCount = await _context.ChecklistCompletions .Where(cc => cc.Checklist.DeviceId == deviceId) .CountAsync(cc => cc.PersianDate.StartsWith($"{year}/{month:D2}"), cancellationToken); var dailyAnalysesCount = await _context.DailyReports .CountAsync(dr => dr.DeviceId == deviceId && dr.PersianYear == year && dr.PersianMonth == month, cancellationToken); // Generate performance summary var performanceSummary = GeneratePerformanceSummary( totalTelemetryRecords, totalAlerts, successfulAlerts, failedAlerts, avgTemp, avgHumidity, avgLux, avgGas, userReportsCount, checklistCompletionsCount); return new MonthlyReportDto { DeviceId = deviceId, DeviceName = device.DeviceName, Year = year, Month = month, TotalAlerts = totalAlerts, SmsAlerts = smsAlerts, CallAlerts = callAlerts, SuccessfulAlerts = successfulAlerts, FailedAlerts = failedAlerts, PowerOutageAlerts = powerOutageAlerts, TotalTelemetryRecords = totalTelemetryRecords, AverageTemperature = avgTemp, MinTemperature = minTemp, MaxTemperature = maxTemp, AverageHumidity = avgHumidity, MinHumidity = minHumidity, MaxHumidity = maxHumidity, AverageLux = avgLux, AverageGasPPM = avgGas, MaxGasPPM = maxGas, UserDailyReportsCount = userReportsCount, ChecklistCompletionsCount = checklistCompletionsCount, DailyAnalysesCount = dailyAnalysesCount, PerformanceSummary = performanceSummary, GeneratedAt = DateTime.UtcNow }; } private string GeneratePerformanceSummary( int totalRecords, int totalAlerts, int successfulAlerts, int failedAlerts, decimal avgTemp, decimal avgHumidity, decimal avgLux, int avgGas, int userReports, int checklistCompletions) { var summary = new List(); summary.Add($"📊 آمار کلی:"); summary.Add($" • تعداد رکوردهای ثبت شده: {totalRecords:N0}"); summary.Add($" • میانگین دما: {avgTemp:F1}°C"); summary.Add($" • میانگین رطوبت: {avgHumidity:F1}%"); summary.Add($" • میانگین نور: {avgLux:F0} لوکس"); if (avgGas > 0) summary.Add($" • میانگین CO: {avgGas} PPM"); summary.Add(""); summary.Add($"🚨 هشدارها:"); summary.Add($" • تعداد کل: {totalAlerts}"); summary.Add($" • موفق: {successfulAlerts}"); if (failedAlerts > 0) summary.Add($" • ناموفق: {failedAlerts} ⚠️"); if (userReports > 0 || checklistCompletions > 0) { summary.Add(""); summary.Add($"📝 فعالیت کاربران:"); if (userReports > 0) summary.Add($" • گزارش‌های روزانه: {userReports}"); if (checklistCompletions > 0) summary.Add($" • تکمیل چک‌لیست: {checklistCompletions}"); } // Performance rating summary.Add(""); var rating = CalculatePerformanceRating(totalRecords, failedAlerts, totalAlerts); summary.Add($"⭐ ارزیابی کلی: {rating}"); return string.Join("\n", summary); } private string CalculatePerformanceRating(int totalRecords, int failedAlerts, int totalAlerts) { if (totalRecords == 0) return "بدون داده"; var failureRate = totalAlerts > 0 ? (double)failedAlerts / totalAlerts : 0; if (failureRate == 0 && totalRecords > 1000) return "عالی ✅"; else if (failureRate < 0.1 && totalRecords > 500) return "خوب 👍"; else if (failureRate < 0.3) return "متوسط ⚠️"; else return "نیاز به بررسی 🔧"; } }