using Portfolio.Domain.Features.TemperatureDay; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.Json; using System.Text.Json.Serialization; using System.Threading.Tasks; namespace Portfolio.Application.Services.NWSWeatherService { public class NWSWeatherService : INWSWeatherService { private readonly HttpClient _httpClient; public NWSWeatherService(HttpClient httpClient) { _httpClient = httpClient; _httpClient.DefaultRequestHeaders.Add("User-Agent", "kira.jiroux@gmail.com"); // Replace with your email ideally } public async Task GetNearestStationAsync(double latitude, double longitude) { var url = $"https://api.weather.gov/points/{latitude},{longitude}"; var response = await _httpClient.GetAsync(url); response.EnsureSuccessStatusCode(); using var stream = await response.Content.ReadAsStreamAsync(); var json = await JsonDocument.ParseAsync(stream); var stationUrl = json.RootElement .GetProperty("properties") .GetProperty("observationStations") .GetString(); if (string.IsNullOrEmpty(stationUrl)) throw new Exception("Could not find station info."); var stationListResponse = await _httpClient.GetAsync(stationUrl); stationListResponse.EnsureSuccessStatusCode(); using var stationStream = await stationListResponse.Content.ReadAsStreamAsync(); var stationJson = await JsonDocument.ParseAsync(stationStream); var firstStation = stationJson.RootElement .GetProperty("features")[0] .GetProperty("properties") .GetProperty("stationIdentifier") .GetString(); return firstStation; } public async Task GetDailyAverageTempAsync(string stationId, DateTime date) { var start = date.ToString("yyyy-MM-dd") + "T00:00:00Z"; var end = date.ToString("yyyy-MM-dd") + "T23:59:59Z"; var url = $"https://api.weather.gov/stations/{stationId}/observations?start={start}&end={end}"; var response = await _httpClient.GetAsync(url); response.EnsureSuccessStatusCode(); using var stream = await response.Content.ReadAsStreamAsync(); var json = await JsonDocument.ParseAsync(stream); var temps = new List(); foreach (var feature in json.RootElement.GetProperty("features").EnumerateArray()) { if (feature.TryGetProperty("properties", out var props) && props.TryGetProperty("temperature", out var tempObj) && tempObj.TryGetProperty("value", out var valueProp) && valueProp.ValueKind == JsonValueKind.Number) { var celsius = valueProp.GetDouble(); if (!double.IsNaN(celsius)) { var fahrenheit = (celsius * 9.0 / 5.0) + 32.0; temps.Add(fahrenheit); } } } if (temps.Count == 0) return null; return temps.Average(); } public async Task> GetTemperatureDataAsync(double latitude, double longitude, int year) { var stationId = await GetNearestStationAsync(latitude, longitude); var result = new List(); var startDate = new DateTime(year, 1, 1); var endDate = new DateTime(year, 12, 31); for (var date = startDate; date <= endDate; date = date.AddDays(1)) { Console.WriteLine($"Fetching {date:yyyy-MM-dd}..."); var avgTemp = await GetDailyAverageTempAsync(stationId, date); if (avgTemp.HasValue) { result.Add(new TemperatureDay { Date = date, AvgTemp = Math.Round(avgTemp.Value, 1) }); } else { Console.WriteLine($"No data for {date:yyyy-MM-dd}"); } await Task.Delay(600); // small delay to be nice to NWS } return result; } } }