using System.Text.Json;
using Microsoft.Extensions.Caching.Memory;

namespace economy.Models.Price.Global
{
    public class GlobalModel
    {
        private readonly Alpha_API _alphaAPI;
        private readonly IMemoryCache _cache;
        private readonly EconomyContext? _context;

        public GlobalModel(Alpha_API alphaAPI, IMemoryCache cache, EconomyContext? context = null)
        {
            _alphaAPI = alphaAPI;
            _cache = cache;
            _context = context;
        }

        // 천연가스 시세 조회
        public async Task<NaturalGas.Response> GetNaturalGasPriceInfo(NaturalGas.Request request)
        {
            string cacheKey = $"Alpha_NATURAL_GAS_{request.Interval}";

            // 캐시에 데이터가 존재하면 반환
            if (_cache.TryGetValue(cacheKey, out NaturalGas.Response cachedData))
            {
                return cachedData;
            }

            NaturalGas.Response parseData = new();

            try
            {
                var uriBuilder = new UriBuilder(_alphaAPI.APIUrl)
                {
                    Path = "/query",
                    Query = $"function=NATURAL_GAS&interval={request.Interval}&apikey={_alphaAPI.APIKey}"
                };

                var response = await _alphaAPI.httpClient.GetAsync(uriBuilder.Uri);

                if (response.IsSuccessStatusCode)
                {
                    var jsonString = await response.Content.ReadAsStringAsync();

                    parseData = JsonSerializer.Deserialize<NaturalGas.Response>(jsonString);

                    if (parseData.Data is not null)
                    {
                        // 캐시에 저장 (메모리 1일 + DB에 마지막 성공 응답 영구 보관)
                        _cache.Set(cacheKey, parseData, TimeSpan.FromDays(1));
                        await SaveDbCacheAsync(cacheKey, jsonString);

                        return parseData;
                    }
                }

                response.EnsureSuccessStatusCode();
            }
            catch (HttpRequestException e)
            {
                Console.WriteLine($"Request error: {e.Message}");
            }

            // 호출 실패/한도 초과 시 DB에 보관된 마지막 성공 응답으로 대체
            var fallback = await LoadDbCacheAsync<NaturalGas.Response>(cacheKey);

            return fallback ?? new NaturalGas.Response();
        }

        // 국제 원자재 시세 조회 (구리, 알루미늄, 밀, 섬유(면화), 설탕, 커피, 원자재 종합지수)
        public async Task<Commodity.Response> GetCommodityPriceInfo(string function, string interval)
        {
            string cacheKey = $"Alpha_{function}_{interval}";

            // 캐시에 데이터가 존재하면 반환
            if (_cache.TryGetValue(cacheKey, out Commodity.Response cachedData))
            {
                return cachedData;
            }

            Commodity.Response parseData = new();

            try
            {
                var uriBuilder = new UriBuilder(_alphaAPI.APIUrl)
                {
                    Path = "/query",
                    Query = $"function={function}&interval={interval}&apikey={_alphaAPI.APIKey}"
                };

                var response = await _alphaAPI.httpClient.GetAsync(uriBuilder.Uri);

                if (response.IsSuccessStatusCode)
                {
                    var jsonString = await response.Content.ReadAsStringAsync();

                    parseData = JsonSerializer.Deserialize<Commodity.Response>(jsonString);

                    if (parseData.Data is not null)
                    {
                        // 캐시에 저장 (메모리 1일 + DB에 마지막 성공 응답 영구 보관)
                        _cache.Set(cacheKey, parseData, TimeSpan.FromDays(1));
                        await SaveDbCacheAsync(cacheKey, jsonString);

                        return parseData;
                    }
                }

                response.EnsureSuccessStatusCode();
            }
            catch (HttpRequestException e)
            {
                Console.WriteLine($"Request error: {e.Message}");
            }

            // 호출 실패/한도 초과 시 DB에 보관된 마지막 성공 응답으로 대체
            var fallback = await LoadDbCacheAsync<Commodity.Response>(cacheKey);

            return fallback ?? new Commodity.Response();
        }

        // 성공 응답을 DB에 upsert (DB 장애 시에도 서비스에는 영향 없음)
        private async Task SaveDbCacheAsync(string cacheKey, string payload)
        {
            if (_context is null)
            {
                return;
            }

            try
            {
                var row = await _context.ApiCache.FindAsync(cacheKey);

                if (row is null)
                {
                    _context.ApiCache.Add(new ApiCacheEntry { CacheKey = cacheKey, Payload = payload, UpdatedAt = DateTime.Now });
                }
                else
                {
                    row.Payload = payload;
                    row.UpdatedAt = DateTime.Now;
                }

                await _context.SaveChangesAsync();
            }
            catch (Exception e)
            {
                Console.WriteLine($"ApiCache save error: {e.Message}");
            }
        }

        // DB에 보관된 마지막 성공 응답 조회 (없거나 DB 장애면 null)
        private async Task<T?> LoadDbCacheAsync<T>(string cacheKey) where T : class
        {
            if (_context is null)
            {
                return null;
            }

            try
            {
                var row = await _context.ApiCache.FindAsync(cacheKey);

                return row is null ? null : JsonSerializer.Deserialize<T>(row.Payload);
            }
            catch (Exception e)
            {
                Console.WriteLine($"ApiCache load error: {e.Message}");

                return null;
            }
        }
    }
}
