using DailyDigestWorker.Models; using System.Globalization; using System.Text; namespace DailyDigestWorker.Services { public class DigestBuilderService : IDigestBuilderService { private readonly ILogger _logger; public DigestBuilderService(ILogger logger) { _logger = logger; } public string BuildDigestText(CurrencyData? currency, CryptoData? crypto, WeatherData? weather, string? newsSummary) { _logger.LogInformation("Начало формирования улучшенного текста дайджеста..."); var sb = new StringBuilder(); var culture = CultureInfo.GetCultureInfo("ru-RU"); var nl = Environment.NewLine; // Используем системный перенос строки для читаемости кода // --- Заголовок --- sb.Append("🗓️ *").Append(DateTime.Now.ToString("dd MMMM yyyy", culture)).Append("*").AppendLine(" | Ежедневный Дайджест (Новокузнецк)"); sb.AppendLine("--------------------------------------"); // Разделитель // --- Блок Погоды (перенесем наверх) --- if (weather != null) { sb.Append(weather.Emoji).Append(" *Погода:* "); sb.Append(weather.TemperatureC.ToString("F0", culture)).Append("°C "); sb.Append($"_(ощущ. {weather.FeelsLikeC.ToString("F0", culture)}°C)_ "); sb.Append("| ").Append(CultureInfo.CurrentCulture.TextInfo.ToTitleCase(weather.Description)); sb.AppendLine(); // Перенос строки после погоды } else { sb.AppendLine("☁️ *Погода:* _(Не удалось получить данные)_"); } sb.AppendLine(); // Доп. отступ // --- Блок Валют --- sb.AppendLine("💰 *Курсы Валют*"); if (currency != null) { sb.AppendLine($"_(на {currency.Date:dd.MM})_"); foreach (var rate in currency.Rates.OrderBy(r => r.Key)) // Сортируем для порядка (EUR, USD) { string symbol = rate.Key == "USD" ? "🇺🇸" : (rate.Key == "EUR" ? "🇪🇺" : "▪️"); sb.AppendLine($" {symbol} {rate.Key}: `{rate.Value.ToString("N2", culture)} ₽`"); // Используем моноширинный шрифт для чисел } } else { sb.AppendLine(" _(Не удалось получить данные)_"); } sb.AppendLine(); // --- Блок Криптовалют --- sb.AppendLine("₿ *Криптовалюты*"); if (crypto != null && crypto.CryptoRates.Any()) { foreach (var cryptoPair in crypto.CryptoRates.OrderBy(p => p.Key)) // Сортируем (Bitcoin, Ethereum) { string cryptoName = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(cryptoPair.Key); var ratesText = new List(); // Сортируем валюты (RUB, USD) foreach (var ratePair in cryptoPair.Value.OrderBy(r => r.Key == "USD" ? 0 : 1)) { string format = ratePair.Key.ToLower() == "usd" ? "N0" : "N2"; string symbol = ratePair.Key.ToLower() == "usd" ? "$" : "₽"; ratesText.Add($"{symbol}{ratePair.Value.ToString(format, culture)}"); // Убрали (USD/RUB) для краткости } sb.AppendLine($" 📈 {cryptoName}: `{string.Join(" / ", ratesText)}`"); // Используем моноширинный } } else { sb.AppendLine(" _(Не удалось получить данные)_"); } sb.AppendLine(); // --- Блок Новостей --- if (!string.IsNullOrWhiteSpace(newsSummary)) { _logger.LogDebug("Добавление блока новостей в дайджест."); sb.AppendLine("📰 *Сводка новостей за сутки*"); // Добавляем саммари, предполагая, что Gemini вернул Markdown-список // Убираем лишние пустые строки из ответа Gemini, если они есть var summaryLines = newsSummary.Trim().Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); foreach (var line in summaryLines) { // Добавляем небольшой отступ к каждой строке новости для лучшего вида sb.Append(" ").AppendLine(line.Trim()); } // sb.AppendLine("---"); // Убрал разделитель после новостей, блок последний } else { _logger.LogDebug("Саммари новостей пустое или не получено, блок новостей не добавляется."); // sb.AppendLine("📰 *Сводка новостей за сутки*"); // sb.AppendLine(" _(Нет новостей или не удалось обработать)_"); } // sb.AppendLine(); // Убрал лишний отступ в конце string result = sb.ToString().TrimEnd(); _logger.LogInformation("Текст дайджеста успешно сформирован (улучшенный)."); _logger.LogDebug("Итоговый текст дайджеста:\n{DigestText}", result); return result; } } }