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<string> 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<double?> 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<double>();

            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<List<TemperatureDay>> GetTemperatureDataAsync(double latitude, double longitude, int year)
        {
            var stationId = await GetNearestStationAsync(latitude, longitude);

            var result = new List<TemperatureDay>();

            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;
        }
    }
}
