using HealthMonitor.Core.Dal;
using HealthMonitor.Core.Query;
using HealthMonitor.Core.Query.Extensions;
using HealthMonitor.Util.Entities.HealthMonitor;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;

namespace HealthMonitor.Service.Cache
{
    public class BloodPressReferenceValueCacheManager
    {
        private readonly ILogger<BloodPressReferenceValueCacheManager> _logger;
        protected readonly IHealthMonitorDataAccessor _dataAccessor;

        private static readonly object _syncLocker = new();
        private readonly MD5 _md5;
        private const string CACHE_KEY_BP_REF_VALUE = "HM_REF_Val_";

        public BloodPressReferenceValueCacheManager(
             IHealthMonitorDataAccessor dataAccessor,
             ILogger<BloodPressReferenceValueCacheManager> logger
            ) 
        {
            _md5 = MD5.Create();
            _dataAccessor = dataAccessor;
            _logger = logger;
        }

        public async Task<HmBloodPressReferenceValue> GetBloodPressReferenceValueAsync(int age, int gender,bool isHypertension)
        {
            var hashModel = new
            {
                Index = $"{age}-{gender}-{isHypertension}"
            };
            var hash = ComputeHash(hashModel);
            var cacheKey = CACHE_KEY_BP_REF_VALUE + $"{hash}";

            var bpRef = await RedisHelper.GetAsync<HmBloodPressReferenceValue>(cacheKey).ConfigureAwait(false);
            if (bpRef == null)
            {
                try
                {
                    bpRef = await _dataAccessor
                    .GetFirstOrDefaultAsync<HmBloodPressReferenceValue>
                    (
                        i =>
                        i.Age.Equals(age) &&
                        i.Gender.Equals(gender) &&
                        i.Hypertension.Equals(isHypertension)
                    ).ConfigureAwait(false);
                    await RedisHelper.SetAsync(cacheKey, JsonConvert.SerializeObject(bpRef));
                   return bpRef;
                }
                catch (Exception ex)
                {
                    _logger.LogError($"{nameof(GetBloodPressReferenceValueAsync)}发生异常:{ex.Message}, {ex.StackTrace}");
                    return new HmBloodPressReferenceValue
                    {
                        Age = 0,
                    };
                }
               
            }

            return bpRef;

        }

        public async Task UpdateBloodPressReferenceValueAsync(HmBloodPressReferenceValue bpRef)
        {
            try
            {
                
                var hashModel = new
                {
                    Index = $"{bpRef.Age}-{bpRef.Gender}-{bpRef.Hypertension}"
                };
                var hash = ComputeHash(hashModel);
                var cacheKey = CACHE_KEY_BP_REF_VALUE + $"{hash}";
                await RedisHelper.SetAsync(cacheKey, JsonConvert.SerializeObject(bpRef));
               
            }
            catch (Exception ex)
            {
                _logger.LogError($"{nameof(UpdateBloodPressReferenceValueAsync)}发生异常:{ex.Message}, {ex.StackTrace}");
                
            }
        }

        public async Task DeleteBloodPressReferenceValueAsync(HmBloodPressReferenceValue bpRef)
        {
            try
            {

                var hashModel = new
                {
                    Index = $"{bpRef.Age}-{bpRef.Gender}-{bpRef.Hypertension}"
                };
                var hash = ComputeHash(hashModel);
                var cacheKey = CACHE_KEY_BP_REF_VALUE + $"{hash}";
                await RedisHelper.DelAsync(cacheKey);
               

            }
            catch (Exception ex)
            {
                _logger.LogError($"{nameof(DeleteBloodPressReferenceValueAsync)}发生异常:{ex.Message}, {ex.StackTrace}");

            }
        }

        private string ComputeHash(object data)
        {
            lock (_syncLocker)
            {
                var value = JsonConvert.SerializeObject(data);
                value = Convert.ToBase64String(_md5.ComputeHash(Encoding.UTF8.GetBytes(value)));
                return value;
            }
        }



    }
}