namespace TaxBaik.Web.Services; using Microsoft.Extensions.Hosting; using TaxBaik.Application.Services; public class TelegramReportBackgroundService( IServiceScopeFactory scopeFactory, ILogger logger) : BackgroundService { private static readonly TimeZoneInfo KoreaTimeZone = GetKoreaTimeZone(); private DateOnly? _lastDailyReportDate; private DateOnly? _lastWeeklyReportWeekStart; protected override async Task ExecuteAsync(CancellationToken stoppingToken) { using var timer = new PeriodicTimer(TimeSpan.FromMinutes(30)); while (await timer.WaitForNextTickAsync(stoppingToken)) { try { var now = TimeZoneInfo.ConvertTime(DateTimeOffset.UtcNow, KoreaTimeZone); await TrySendReportsAsync(now, stoppingToken); } catch (Exception ex) { logger.LogError(ex, "Telegram report background loop failed"); } } } private async Task TrySendReportsAsync(DateTimeOffset nowKst, CancellationToken ct) { if (nowKst.Hour is 9 or 10) await SendDailyIfNeededAsync(DateOnly.FromDateTime(nowKst.DateTime), ct); if (nowKst.DayOfWeek == DayOfWeek.Monday && nowKst.Hour is 9 or 10) await SendWeeklyIfNeededAsync(DateOnly.FromDateTime(nowKst.DateTime).AddDays(-7), ct); } private async Task SendDailyIfNeededAsync(DateOnly date, CancellationToken ct) { if (_lastDailyReportDate == date) return; using var scope = scopeFactory.CreateScope(); var reportService = scope.ServiceProvider.GetRequiredService(); var telegram = scope.ServiceProvider.GetRequiredService(); var report = await reportService.BuildDailyReportAsync(date, ct); await telegram.SendReportAsync("일간 세무/상담 현황 리포트", TelegramReportService.FormatDailyMessage(report), ct); _lastDailyReportDate = date; logger.LogInformation("Daily telegram report sent for {Date}", date); } private async Task SendWeeklyIfNeededAsync(DateOnly weekStart, CancellationToken ct) { if (_lastWeeklyReportWeekStart == weekStart) return; using var scope = scopeFactory.CreateScope(); var reportService = scope.ServiceProvider.GetRequiredService(); var telegram = scope.ServiceProvider.GetRequiredService(); var report = await reportService.BuildWeeklyReportAsync(weekStart, ct); await telegram.SendReportAsync("주간 세무/매출 종합 리포트", TelegramReportService.FormatWeeklyMessage(report), ct); _lastWeeklyReportWeekStart = weekStart; logger.LogInformation("Weekly telegram report sent for {WeekStart}", weekStart); } private static TimeZoneInfo GetKoreaTimeZone() { try { return TimeZoneInfo.FindSystemTimeZoneById("Korea Standard Time"); } catch (TimeZoneNotFoundException) { return TimeZoneInfo.FindSystemTimeZoneById("Asia/Seoul"); } } }