using Fest.WebApi.DL;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

namespace Fest.WebApi.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class WeatherController : ControllerBase
    {
        private readonly IConfiguration _configuration;
        private readonly HttpClient _httpClient;
        private readonly WeatherDbContext _dbContext;

        public WeatherController(IConfiguration configuration, HttpClient httpClient, WeatherDbContext dbContext)
        {
            _configuration = configuration;
            _httpClient = httpClient;
            _dbContext = dbContext;
        }

        [HttpGet("{zip}")]
        public async Task<object> GetAsync(string zip)
        {
            Geo? geo = await GetGeoAsync(zip);
            if (geo == null || geo.Cod != null)
                return NotFound($"Zip not found: {geo?.Message}");

            Weather? weather = await GetWeatherAsync(geo.Lat, geo.Lon);
            if (weather?.Cod != 200)
                return NotFound($"Weather not found: {weather?.Message}");

            string city = weather.Name;
            decimal tempF = weather.Main.Temp;

            Guid? clientId = GetXClientId(Request);

            if (clientId != null)
                await WriteRequestHistoryItemAsync(clientId.Value, city, tempF);

            return new { City = city, TempF = tempF };
        }

        [HttpGet("history")]
        public async Task<object> GetHistoryAsync()
        {
            Guid? clientId = GetXClientId(Request);
            if (!clientId.HasValue)
                return NotFound($"Client Id not found");

            return await GetRequestHistoryAsync(clientId.Value);
        }

        #region private

        private async Task WriteRequestHistoryItemAsync(Guid clientId, string city, decimal tempF)
        {
            _dbContext.Add(new RequestHistoryItem { ClientId = clientId, City = city, TempF = tempF });
            await _dbContext.SaveChangesAsync();
        }

        private Task<List<RequestHistoryItem>> GetRequestHistoryAsync(Guid clientId)
            => _dbContext.RequestHistoryItems.Where(x => x.ClientId == clientId)
                .OrderByDescending(x => x.Id)
                .ToListAsync();

        private Guid? GetXClientId(HttpRequest request)
        {
            var clientIdFromHeader =
                request.Headers.FirstOrDefault(h =>
                           h.Key.Equals("X-Client-Id", StringComparison.InvariantCultureIgnoreCase)).Value
                       .FirstOrDefault();

            return Guid.TryParse(clientIdFromHeader, out var clientId)
                ? clientId
                : null;
        }

        private async Task<Geo?> GetGeoAsync(string zip)
        {
            var response = await _httpClient
                .GetAsync($"https://api.openweathermap.org/geo/1.0/zip?zip={zip}&appid={_configuration["AppId"]}");

            return await response.Content.ReadFromJsonAsync<Geo>();
        }

        private async Task<Weather?> GetWeatherAsync(decimal lat, decimal lon)
        {
            var response = await _httpClient
                    .GetAsync($"https://api.openweathermap.org/data/2.5/weather?lat={lat}&lon={lon}&appid={_configuration["AppId"]}");

            return await response.Content.ReadFromJsonAsync<Weather>();
        }

        #endregion
    }
}