using AsbCloudApp.Services;
using System.Net.Http;
using AsbCloudApp.Data;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using System;

namespace AsbCloudInfrastructure.Services
{
    public class TimeZoneService : ITimeZoneService
    {
        class TimeZoneInfo
        {
            public string Sunrise { get; set; }
            public double Lng { get; set; }
            public double Lat { get; set; }
            public string CountryCode { get; set; }
            public double GmtOffset { get; set; }
            public double RawOffset { get; set; }
            public string Sunset { get; set; }
            public string TimezoneId { get; set; }
            public double DstOffset { get; set; }
            public string CountryName { get; set; }
            public string Time { get; set; }
        }

        private readonly string timeZoneApiUrl = "http://api.geonames.org/timezoneJSON";
        private readonly string timezoneApiUserName = "asbautodrilling";

        public async Task<TelemetryTimeZoneDto> GetByCoordinatesAsync(double latitude, double longitude, CancellationToken token)
        {
            var lat = latitude.ToString(System.Globalization.CultureInfo.InvariantCulture);
            var lng = longitude.ToString(System.Globalization.CultureInfo.InvariantCulture);

            var url =
                $"{timeZoneApiUrl}?lat={lat}&lng={lng}&username={timezoneApiUserName}";

            using var client = new HttpClient();

            var response = await client.GetAsync(url, token)
                .ConfigureAwait(false);

            var responseJson = await response.Content.ReadAsStringAsync(token)
                .ConfigureAwait(false);

            if (!(responseJson.Contains("timezoneId") && responseJson.Contains("dstOffset")))
                return null;

            var options = new JsonSerializerOptions
            {
                PropertyNameCaseInsensitive = true
            };
            var timeZoneInfo = JsonSerializer.Deserialize<TimeZoneInfo>(responseJson, options);
            
            return new TelemetryTimeZoneDto
            {
                Hours = timeZoneInfo.DstOffset,
                IsOverride = false,
                TimeZoneId = timeZoneInfo.TimezoneId,
            };
        }

        public DateTime DateToUtc(DateTime date, double remoteTimezoneOffsetHours)
        {
            if (date == default)
                return new DateTime(0, DateTimeKind.Utc);

            var newDate = date.Kind switch
            {
                DateTimeKind.Local => date.ToUniversalTime(),
                DateTimeKind.Unspecified => date.AddHours(-remoteTimezoneOffsetHours),
                _ => date,
            };
            return DateTime.SpecifyKind(newDate, DateTimeKind.Utc);
        }

        public DateTime DateToTimeZone(DateTime date, double remoteTimezoneOffsetHours)
        {
            if (date == default)
                return new DateTime(0, DateTimeKind.Unspecified);

            var newDate = date.Kind switch
            {
                DateTimeKind.Local => date.ToUniversalTime().AddHours(remoteTimezoneOffsetHours),
                DateTimeKind.Utc => date.AddHours(remoteTimezoneOffsetHours),
                _ => date,
            };
            return DateTime.SpecifyKind(newDate, DateTimeKind.Unspecified);
        }
    }
}