using dodohold.core;
using MySql.Data.MySqlClient;
using System.Data;


namespace molilian.core
{
    public partial class EndPointCore
    {
        private static readonly object _lockObj = new();
        private static IEnumerable<EndPointDTO> _cached;

        public static string GetRedisServer(EndPointDTO node)
        {
#if DEBUG
            return node.name switch
            {
                "bj" => "101.200.152.61:6379,password=pKBiS4ka2IpXayIdcx00,defaultDatabase=0,idleTimeout=20000,preheat=3,tryit=2,ssl=false,prefix=webhook",
                "gz" => "8.138.110.158:6379,password=pKBiS4ka2IpXayIdcx00,defaultDatabase=0,idleTimeout=20000,preheat=3,tryit=2,ssl=false,prefix=webhook",
                "coupon1" => "123.56.185.166:6379,password=pKBiS4ka2IpXayIdcx00,defaultDatabase=0,idleTimeout=20000,preheat=3,tryit=2,ssl=false,prefix=coupon",
                _ => string.Empty
            };
#else
    return node.redis_server;
#endif
        }

        public static string CurrentEndPoint { get; set; }
        static EndPointCore()
        {
            CurrentEndPoint = Environment.GetEnvironmentVariable("EndPoint");
        }



        public static IDbConnection GetDbConnection(string connString)
        {
            var conn = new MySqlConnection(connString);
            return conn;
        }

        public static EndPointDTO GetOne(string node)
        {
            var list = List();
            if (!list.Any()) return null;
            var item = list.Where(s => s.name == node).FirstOrDefault();
            return item;
        }


        public static EndPointDTO GetCouponAdmin()
        {
            var list = List();
            if (!list.Any()) return null;
            var item = list.Where(s => s.is_coupon_api && !s.is_public_api).FirstOrDefault();


#if DEBUG
            // item.db_server = "Server= rm-2ze49fcn8e28e6gzu3o.rwlb.rds.aliyuncs.com; Port=3306; Database=coupon; Uid=coupon; Pwd=67ktWBmw5G4yMs4J;SslMode=None;CharSet=utf8mb4;ConnectionTimeout=60;";
#endif
            /*   
Server=rm-2zey1jqxnoqy9mcc0zo.rwlb.rds.aliyuncs.com; Port=3306; Database=taoke; Uid=taoke; Pwd=67ktWBmw5G4yMs4J;SslMode=None;CharSet=utf8mb4;ConnectionTimeout=60
Server=rm-2zey1jqxnoqy9mcc0zo.rwlb.rds.aliyuncs.com; Port=3306; Database=taoke; Uid=taoke; Pwd=67ktWBmw5G4yMs4J;SslMode=None;CharSet=utf8mb4;ConnectionTimeout=60
Server=rm-2zey1jqxnoqy9mcc0zo.rwlb.rds.aliyuncs.com; Port=3306; Database=taoke; Uid=taoke; Pwd=67ktWBmw5G4yMs4J;SslMode=None;CharSet=utf8mb4;ConnectionTimeout=60
Server=rm-2ze74506m3gfsqe7mco.rwlb.rds.aliyuncs.com; Port=3306; Database=coupon; Uid=coupon; Pwd=67ktWBmw5G4yMs4J;SslMode=None;CharSet=utf8mb4;ConnectionTimeout=60;
             
             */
            return item;
        }

        public static EndPointDTO GetParseAdmin()
        {
            var list = List();
            if (!list.Any()) return null;
            var item = list.Where(s => !s.is_coupon_api && !s.is_public_api).FirstOrDefault();

#if DEBUG
            item.db_server = "Server=rm-2ze49fcn8e28e6gzu3o.rwlb.rds.aliyuncs.com; Port=3306; Database=taoke; Uid=taoke; Pwd=67ktWBmw5G4yMs4J;SslMode=None;CharSet=utf8mb4;ConnectionTimeout=60;";
#endif
            return item;
        }

        public static IEnumerable<EndPointDTO> List(bool force = false)
        {
            if (!force && _cached != null) return _cached;

            string cache_key = $"cache:end_point";
            var list = RedisHelper.Get<IEnumerable<EndPointDTO>>(cache_key);
            if (force || list == null)
            {
                lock (_lockObj)
                {
                    list = new DBContext.Table("end_point")
                        .Where("status=@status", new { status = 1 })
                        .Select<EndPointDTO>();
                    if (list == null) return default;
                    RedisHelper.Set(cache_key, list, 30 * 86400);
                }
            }
            _cached = list;
            return list;
        }
        public static void Refresh()
        {
            _ = List(true);
        }

        public static List<T> ProcessEndPointNodes<T>(Func<EndPointDTO, T> nodeAction, bool force = false)
        {
            var resultList = new List<T>();
            var list = List(force);
            foreach (var node in list)
            {
                var result = nodeAction(node);
                if (result != null) resultList.Add(result);
            }
            return resultList;
        }
        public static async Task<List<T>> ProcessEndPointNodesTaskAsync<T>(Func<EndPointDTO, Task<T>> nodeAction, bool force = false)
        {
            var resultList = new List<T>();
            var list = List(force);

            var tasks = list.Select(node => nodeAction(node));
            var results = await Task.WhenAll(tasks);

            return results.Where(result => result != null).ToList();

            //foreach (var node in list)
            //{
            //    var result = await nodeAction(node);
            //    if (result != null) resultList.Add(result);
            //}
            //return resultList;
        }

        public static async Task ProcessEndPointNodesAsync(Func<EndPointDTO, Task> nodeAction, bool force = false)
        {
            var list = List(force);
            var tasks = list.Select(node => nodeAction(node));
            await Task.WhenAll(tasks);
        }


        public static async Task NotifyReload(bool onlyAccount = false, CancellationToken cancellationToken = default)
        {
            await ProcessEndPointNodesAsync(async node =>
            {
                try
                {
                    string url = $"{node.api_server}Task_70160bd632/reload";
                    if (onlyAccount) url = $"{node.api_server}Task_70160bd632/reloadAccount";
                    await new WebClientUtility().RequestAsync(url, "GET", cancellationToken);
                }
                catch (Exception ex)
                {
                    _ = new LoggerLibrary("NotifyReload", "error")
                    .Info(node.Convert2Json())
                    .Info(ex.Message, ex.StackTrace)
                    .SaveAsync();

                    NotifyCore.Notify(new NifyMessage
                    {
                        message = $"【NotifyReload异常】{node.description}\n{ex.Message}\n{ex.StackTrace}",
                        priority = NifyMessagePriority.high,
                        tags = ["red_circle"]
                    });
                }
            });
        }

        public static List<(string, string)> NotifyCheckDeepUrl(int accountid, CancellationToken cancellationToken = default)
        {
            var result = ProcessEndPointNodes<(string, string)>(node =>
            {
                try
                {
                    if (!node.is_public_api) return (node.name, "break");
                    if (!node.status) return (node.name, "账号下线");

                    string url = $"{node.api_server}Task_70160bd632/CheckDeepUrl?accountid={accountid}";
                    var result = new WebClientUtility().Request(url, "GET");
                    string body = result.Body();
                    var root = body.Convert2JsonElement();
                    var message = root.Read<string>("message", string.Empty);
                    return (node.name, message);


                }
                catch (Exception ex)
                {
                    _ = new LoggerLibrary("CheckDeepUrl", "error")
                    .Info(node.Convert2Json(), $"accountid:\t{accountid}")
                    .Info(ex.Message, ex.StackTrace)
                    .SaveAsync();

                    NotifyCore.Notify(new NifyMessage
                    {
                        message = $"【CheckDeepUrl异常】{node.description}\n{ex.Message}\n{ex.StackTrace}",
                        priority = NifyMessagePriority.high,
                        tags = ["red_circle"]
                    });
                    return (node.name, ex.Message);
                }
            });
            return result;
        }


        public static async Task NotifyChangeSuspend(int accountId, string endpoint, bool release = false, int? durationSeconds = null, CancellationToken cancellationToken = default)
        {
            await ProcessEndPointNodesAsync(async node =>
            {
                string post = string.Empty;
                try
                {
                    if (string.Equals(node.name, CurrentEndPoint, StringComparison.OrdinalIgnoreCase)) return;

                    string url = $"{node.api_server}api/TkEndpoint/ChangeSuspend";
                    post = new
                    {
                        accountId,
                        endpoint,
                        release,
                        durationSeconds
                    }.Convert2Json();
                    await new WebClientUtility().Post(post).RequestAsync(url, "POST", cancellationToken);
                }
                catch (Exception ex)
                {
                    _ = new LoggerLibrary("TkEndpoint", "ChangeSuspend_error")
                    .Info(node.Convert2Json(), post)
                    .Info(ex.Message, ex.StackTrace)
                    .SaveAsync();

                    NotifyCore.Notify(new NifyMessage
                    {
                        message = $"【TkEndpoint异常】ChangeSuspend\t{node.description}\n{post}\n{ex.Message}\n{ex.StackTrace}",
                        priority = NifyMessagePriority.high,
                        tags = ["red_circle"]
                    });
                }
            });
        }


        public static List<(string, string)> TkEndpointGetStatus(int accountid, CancellationToken cancellationToken = default)
        {
            var result = ProcessEndPointNodes<(string, string)>(node =>
            {
                try
                {
                    if (!node.is_public_api) return (node.name, "break");
                    if (!node.status) return (node.name, "账号下线");

                    string url = $"{node.api_server}api/TkEndpoint/GetStatus";
                    var result = new WebClientUtility().Request(url, "POST");
                    string body = result.Body();
                    var root = body.Convert2JsonElement();
                    var message = root.Read<string>("message", string.Empty);
                    return (node.name, message);
                }
                catch (Exception ex)
                {
                    _ = new LoggerLibrary("GetStatus", "error")
                    .Info(node.Convert2Json(), $"accountid:\t{accountid}")
                    .Info(ex.Message, ex.StackTrace)
                    .SaveAsync();

                    NotifyCore.Notify(new NifyMessage
                    {
                        message = $"【TkEndpoint异常】GetStatus\t{node.description}\n{ex.Message}\n{ex.StackTrace}",
                        priority = NifyMessagePriority.high,
                        tags = ["red_circle"]
                    });
                    return (node.name, ex.Message);
                }
            });
            return result;
        }



    }
}
