using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using dodohold.core;
using System.Threading.Channels;
using YunhuiKit;


namespace molilian.core
{
    public partial class RiskControlCore
    {
        private static Dictionary<string, int> _calls = new();
        private static Dictionary<string, decimal> _incomeAmt = new();

        public static void Refresh()
        {
            _incomeAmt = [];
        }
        public static void ResetCalls()
        {
            _calls = [];
        }
        internal static async Task CallsIncrByAsync(TkChannelEnum channel, int accountId)
        {
            await CallsIncrByAsync(channel, accountId, DateTime.Now.ToString("yyyyMMddHHmm"), 300);
            await CallsIncrByAsync(channel, accountId, DateTime.Now.ToString("yyyyMMddHH"), 14400);
            await CallsIncrByAsync(channel, accountId, DateTime.Now.ToString("yyyyMMdd"));
        }

        internal static async Task CallsIncrByAsync(TkChannelEnum channel, int accountId, string flag, int expire = 259200)
        {
            string key = $"{channel}:{accountId}:{flag}";
            if (_calls.TryGetValue(key, out int value))
            {
                _calls[key] = ++value;
            }
            else
            {
                _calls[key] = 1;
            }
            string cache_key = $":RiskControl:calls:{key}";
            await RedisKit.IncrByAsync(cache_key);
            await RedisKit.ExpireAsync(cache_key, expire);

        }

        internal static async Task SetCallsAsync(TkChannelEnum channel, int accountId, string flag, int val)
        {
            string key = $"{channel}:{accountId}:{flag}";
            _calls.TryAdd(key, val);
            string cache_key = $":RiskControl:calls:{key}";
            await RedisHelper.SetAsync(cache_key, val);
            await RedisHelper.ExpireAsync(cache_key, 3 * 86400);
        }
        public static async Task<int> GetAllNodesCallsAsync(TkChannelEnum channel, int accountId, string flag)
        {
            var key = $"{channel}:{accountId}:{flag}";
            try
            {
                var tasks = EndPointCore.List()
                    .Where(node => node.is_public_api && !string.IsNullOrEmpty(node.redis_server))
                    .Select(async node =>
                    {
                        try
                        {
                            var redisServer = EndPointCore.GetRedisServer(node);
                            if (string.IsNullOrEmpty(redisServer)) return 0;

                            var cacheKey = $":RiskControl:calls:{key}";
                            using var scope = await RedisClientFactory.CreateScopeAsync(redisServer);
                            int count = await scope.Client.GetAsync<int>(cacheKey);
                            return count;
                        }
                        catch (Exception ex) { }
                        return 0;
                    });

                var results = await Task.WhenAll(tasks);
                var totalCalls = results.Sum();
                _calls.TryAdd(key, totalCalls);
                return totalCalls;
            }
            catch (Exception)
            {
                // TODO: 添加日志
                return 0;
            }
        }


        internal static async Task SetTkEndpointCallsAsync(int accountId, int ep_id, string flag, int val)
        {
            string key = $"tk_endpoint:{accountId}:{ep_id}:{flag}";
            if (_calls.ContainsKey(key))
            {
                _calls[key] = val;
            }
            else
            {
                _calls[key] = val;
            }
            string cache_key = $":RiskControl:calls:{key}";
            await RedisHelper.IncrByAsync(cache_key);
            await RedisHelper.ExpireAsync(cache_key, 3 * 86400);
        }


        public static async Task<int> GetAllNodesTkEndpointCallsAsync(int accountId, int ep_id, string flag)
        {
            string key = $"tk_endpoint:{accountId}:{ep_id}:{flag}";
            try
            {
                var tasks = EndPointCore.List()
                    .Where(node => node.is_public_api && !string.IsNullOrEmpty(node.redis_server))
                    .Select(async node =>
                    {
                        try
                        {
                            var redisServer = EndPointCore.GetRedisServer(node);
                            if (string.IsNullOrEmpty(redisServer)) return 0;

                            string cacheKey = $":RiskControl:calls:{key}";
                            using var scope = await RedisClientFactory.CreateScopeAsync(redisServer);
                            return await scope.Client.GetAsync<int>(cacheKey);
                        }
                        catch (Exception ex) { }
                        return 0;
                    });

                var results = await Task.WhenAll(tasks);
                var totalCalls = results.Sum();
                _calls.TryAdd(key, totalCalls);
                return totalCalls;
            }
            catch (Exception)
            {
                // TODO: 添加日志
                return 0;
            }
        }

        public static int GetCalls(TkChannelEnum channel, int accountId, string flag)
        {
            try
            {
                string key = $"{channel}:{accountId}:{flag}";
                if (_calls.ContainsKey(key)) return _calls[key];

                string cache_key = $":RiskControl:calls:{key}";
                int num = RedisHelper.Get<int>(cache_key);
                _calls.TryAdd(key, num);
                return num;
            }
            catch (Exception ex) { return 0; }
        }

        internal static async Task SaveIncomeAmtAsync(TkChannelEnum channel, string accountName, decimal income_amt)
        {
            string key = $"{channel}:{accountName}:{DateTime.Now:yyyyMMdd}";
            lock (_incomeAmt)
            {
                if (!_incomeAmt.TryAdd(key, income_amt))
                    _incomeAmt[key] = income_amt;
            }
            string cache_key = $":RiskControl:{key}:income_amt";
            try
            {
                var tasks = EndPointCore.List()
                    .Where(node => node.is_public_api && !string.IsNullOrEmpty(node.redis_server))
                    .Select(async node =>
                    {
                        try
                        {
                            var redisServer = EndPointCore.GetRedisServer(node);
                            if (string.IsNullOrEmpty(redisServer)) return false;

                            using var scope = await RedisClientFactory.CreateScopeAsync(redisServer);
                            return await scope.Client.SetAsync(cache_key, income_amt, 3 * 86400);
                        }
                        catch (Exception ex)
                        {
                            return false;
                        }
                    });

                await Task.WhenAll(tasks);
            }
            catch (Exception)
            {
            }
        }



        public static decimal GetIncomeAmt(TkChannelEnum channel, string accountName)
        {
            try
            {
                string key = $"{channel}:{accountName}:{DateTime.Now:yyyyMMdd}";
                if (_incomeAmt.ContainsKey(key)) return _incomeAmt[key];

                string cache_key = $":RiskControl:{key}:income_amt";
                return RedisHelper.Get<decimal>(cache_key);
            }
            catch (Exception ex) { return 0; }
        }


        public static string GetRiskCookie(string accountName)
        {
            try
            {
                string cache_key = $":RiskControl:riskCookie:{accountName}";
                return RedisHelper.Get<string>(cache_key);
            }
            catch (Exception ex) { return null; }
        }

        public static bool SetRiskCookie(string accountName, string flagVal)
        {
            try
            {
                string cache_key = $":RiskControl:riskCookie:{accountName}";
                return RedisHelper.Set(cache_key, flagVal);
            }
            catch (Exception ex) { return false; }
        }

    }

}
