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 Dataoke;
using Google.Protobuf.WellKnownTypes;
using System.Diagnostics;
using System.Text.Json;
using TencentCloud.Tcm.V20210413.Models;
using System.Security.Cryptography;
using System.Collections.Concurrent;
using YunhuiKit;
using System.Xml.Linq;


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

        private static string _end_point;
        private static Dictionary<string, decimal> _incomeAmt = new();
        private static ConcurrentDictionary<int, DateTime> _suspend = new();

        // 移除本地内存统计，改用 Redis 存储

        private static SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);

        static PddPoolCore()
        {
            _end_point = Environment.GetEnvironmentVariable("EndPoint");
        }

        /// <summary>
        /// 获取一个账号用于处理请求
        /// 使用平滑加权轮询算法（Smooth Weighted Round-Robin）实现流量均衡分配
        /// </summary>
        public static PddPoolDTO? GetOne(PddUnionWorkMode mode, int accountid = 0, string parse_type = "")
        {
            return GetOne(mode, new UnionParseRequest
            {
                AccountId = accountid
            }, parse_type);
        }

        public static PddPoolDTO? GetOne(PddUnionWorkMode mode, UnionParseRequest request, string parse_type = "")
        {
            var list = List();
            if (!list.Any()) return null;

            // 按 parse_type 过滤
            if ("dp".Equals(parse_type))
            {
                list = list.Where(item => "dp".Equals(item.parse_type)).ToList();
                if (!list.Any()) return null;
            }
            else
            {
                list = list.Where(item => string.IsNullOrEmpty(item.parse_type)).ToList();
                if (!list.Any()) return null;
            }

            if (!string.IsNullOrEmpty(request.RiskStrategy) && !"os".Equals(request.RiskStrategy) && request.LaunchScene != -1)
            {
                list = list.Where(item => request.RiskStrategy.Equals(item.riskStrategy) && item.launchScene == request.LaunchScene).ToList();
                if (!list.Any()) return null;
            }
            else
            {
                list = list.Where(item => string.IsNullOrEmpty(item.riskStrategy)).ToList();
                if (!list.Any()) return null;
            }

            // 过滤出符合条件的候选账号
            var candidates = list.Where(e => IsMatch(e, mode, request.AccountId)).ToList();
            if (!candidates.Any()) return null;

            // 使用平滑加权轮询算法选择账号
            return SmoothWeightedRoundRobin(candidates, parse_type);
        }

        /// <summary>
        /// 基于最后使用时间的调度策略（并发安全版本）
        /// 选择"距离上次使用时间最长"且"超过cis_limit间隔"的账号
        ///
        /// 优势：
        /// 1. 不区分新老账号，一视同仁（无历史记录的账号返回DateTime.MinValue，自然会被优先选中）
        /// 2. 自然满足cis_limit要求（距离时间 < limit 会被跳过）
        /// 3. 优先选择"休息最久"的账号，最大化每个账号的休息时间
        /// 4. 简单直观，易于调试和理解
        /// 5. 并发安全：使用Redis原子操作预留账号，避免多个请求竞争同一账号
        /// </summary>
        private static PddPoolDTO? SmoothWeightedRoundRobin(List<PddPoolDTO> candidates, string parse_type)
        {
            if (!candidates.Any()) return null;
#if DEBUG

            var single = candidates[0];
            return single;
#else
            if (candidates.Count == 1)
            {
                var single = candidates[0];
                // 尝试预留账号（并发安全）
                if (TryReserveAccount(single.id, parse_type, single.cis_limit))
                {
                    return single;
                }
                return null; // 预留失败，说明账号已被其他请求占用
            }
#endif

            try
            {
                string groupKey = string.IsNullOrEmpty(parse_type) ? "default" : parse_type;
                var now = DateTime.Now;

                // 候选账号列表：记录每个账号的空闲时长
                var accountsWithIdleTime = new List<(PddPoolDTO account, long idleMs)>();

                foreach (var account in candidates)
                {
                    // 获取账号最后使用时间
                    var lastUsedTime = GetAccountLastUsedTime(account.id, groupKey);

                    // 计算距离现在的时间差（毫秒）
                    long idleMs = (long)(now - lastUsedTime).TotalMilliseconds;

                    // 如果设置了 cis_limit，必须满足间隔要求
                    if (account.cis_limit > 0 && idleMs < account.cis_limit)
                    {
                        continue; // 跳过未满足间隔要求的账号
                    }

                    accountsWithIdleTime.Add((account, idleMs));
                }

                // 如果没有满足条件的账号，返回null
                if (!accountsWithIdleTime.Any()) return null;

                // 按照空闲时间降序排序，优先尝试"休息最久"的账号
                var sortedAccounts = accountsWithIdleTime
                    .OrderByDescending(x => x.idleMs)
                    .ToList();

                // 依次尝试预留账号（从空闲时间最长的开始）
                foreach (var (account, idleMs) in sortedAccounts)
                {
                    // 尝试原子预留此账号
                    if (TryReserveAccount(account.id, groupKey, account.cis_limit))
                    {
                        // 预留成功，更新最后使用时间
                        SetAccountLastUsedTime(account.id, groupKey, now);
                        Console.WriteLine($"[PDD] Selected account {account.id} ({account.name}), idle time: {Math.Round(idleMs / 1000.0, 2)}s");
                        return account;
                    }
                    else
                    {
                        // 预留失败，说明此账号已被其他并发请求占用，尝试下一个
                        Console.WriteLine($"[PDD] Account {account.id} ({account.name}) is reserved by another request, trying next...");
                    }
                }

                // 所有满足条件的账号都已被占用
                Console.WriteLine($"[PDD] All available accounts are reserved, no account available");
                return null;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Idle time selection failed: {ex.Message}, fallback to simple strategy");

                // 降级策略：使用原有的最少使用次数算法
                return candidates
                    .OrderBy(account => GetCurrentDayUsageFromRedis(account.id))
                    .ThenBy(account => Guid.NewGuid())
                    .FirstOrDefault();
            }
        }

        /// <summary>
        /// 尝试原子预留账号（并发安全）
        /// 使用 Redis SET NX EX 实现原子操作，避免多个请求竞争同一账号
        /// </summary>
        /// <param name="accountId">账号ID</param>
        /// <param name="groupKey">分组键</param>
        /// <param name="cisLimit">请求间隔限制（毫秒），0表示无限制</param>
        /// <returns>true=预留成功，false=账号已被占用</returns>
        private static bool TryReserveAccount(int accountId, string groupKey, int cisLimit)
        {
            try
            {
                string reserveKey = $"pdd_account_reserved:{groupKey}:{accountId}";

                // 如果没有设置 cis_limit，使用默认100ms的预留时间（防止极端并发）
                int expireSeconds = cisLimit > 0 ? (int)Math.Ceiling(cisLimit / 1000.0) : 1;

                // 使用 Redis SET NX EX 原子操作（一次性完成设置和过期时间）
                // 等价于 Redis 命令: SET key value NX EX seconds
                // 如果 key 不存在则设置成功（返回true），如果已存在则失败（返回false）
                // 注意：必须使用原子操作，SetNx + Expire 两步操作会有竞态条件！
                bool reserved = RedisHelper.Set(reserveKey, 1, expireSeconds, CSRedis.RedisExistence.Nx);
                return reserved;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Failed to reserve account {accountId}: {ex.Message}");
                // 预留失败时保守处理：假设账号不可用
                return false;
            }
        }

        /// <summary>
        /// 获取账号最后使用时间
        /// </summary>
        private static DateTime GetAccountLastUsedTime(int accountId, string groupKey)
        {
            try
            {
                string key = $"pdd_last_used_time:{groupKey}:{accountId}";
                var timestamp = RedisHelper.Get<long>(key);

                if (timestamp > 0)
                {
                    return DateTimeOffset.FromUnixTimeMilliseconds(timestamp).LocalDateTime;
                }

                // 如果没有记录，返回很久以前的时间（确保新账号和长期未使用的账号能被优先选中）
                return DateTime.MinValue;
            }
            catch
            {
                return DateTime.MinValue;
            }
        }

        /// <summary>
        /// 设置账号最后使用时间
        /// </summary>
        private static void SetAccountLastUsedTime(int accountId, string groupKey, DateTime time)
        {
            try
            {
                string key = $"pdd_last_used_time:{groupKey}:{accountId}";
                long timestamp = new DateTimeOffset(time).ToUnixTimeMilliseconds();

                // 设置过期时间为24小时，避免数据积累
                RedisHelper.Set(key, timestamp, 86400);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Failed to set last used time for {accountId}: {ex.Message}");
            }
        }

        /// <summary>
        /// 获取账号的静态权重
        /// 可以根据账号的 daily_calls_limit 或其他因素动态计算
        /// </summary>
        private static int GetAccountStaticWeight(int accountId)
        {
            try
            {
                string key = $"pdd_account_weight:{accountId}";
                int weight = RedisHelper.Get<int>(key);

                // 如果没有设置，返回默认权重100
                if (weight <= 0)
                {
                    // 可以基于账号的限额动态计算默认权重
                    var account = List()?.FirstOrDefault(a => a.id == accountId);
                    if (account != null && account.daily_calls_limit > 0)
                    {
                        // 将日限额映射到权重：每1000次调用对应权重10
                        weight = Math.Max(10, Math.Min(1000, account.daily_calls_limit / 100));
                    }
                    else
                    {
                        weight = 100; // 默认权重
                    }
                }

                return weight;
            }
            catch
            {
                return 100; // 异常时返回默认权重
            }
        }

        /// <summary>
        /// 设置账号的静态权重
        /// </summary>
        public static void SetAccountStaticWeight(int accountId, int weight)
        {
            try
            {
                if (weight < 1) weight = 1;
                if (weight > 1000) weight = 1000;

                string key = $"pdd_account_weight:{accountId}";
                RedisHelper.Set(key, weight, 30 * 86400); // 30天过期
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Failed to set account weight for {accountId}: {ex.Message}");
            }
        }

        /// <summary>
        /// 获取账号的当前动态权重
        /// </summary>
        private static int GetAccountCurrentWeight(int accountId, string groupKey)
        {
            try
            {
                string key = $"pdd_current_weight:{groupKey}:{accountId}";
                return RedisHelper.Get<int>(key);
            }
            catch
            {
                return 0;
            }
        }

        /// <summary>
        /// 设置账号的当前动态权重
        /// </summary>
        private static void SetAccountCurrentWeight(int accountId, string groupKey, int weight)
        {
            try
            {
                string key = $"pdd_current_weight:{groupKey}:{accountId}";
                RedisHelper.Set(key, weight, 3600); // 1小时过期，自动重置
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Failed to set current weight for {accountId}: {ex.Message}");
            }
        }

        /// <summary>
        /// 重置所有账号的动态权重（用于调试或重新初始化）
        /// </summary>
        public static void ResetAllWeights(string groupKey = "default")
        {
            try
            {
                var accounts = List()?.Where(a => a.status && a.enable_parse).ToList();
                if (accounts == null || !accounts.Any()) return;

                foreach (var account in accounts)
                {
                    string key = $"pdd_current_weight:{groupKey}:{account.id}";
                    RedisHelper.Del(key);
                }

                Console.WriteLine($"Reset weights for {accounts.Count} accounts in group '{groupKey}'");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Failed to reset weights: {ex.Message}");
            }
        }

        private static int GetCurrentDayUsageFromRedis(int accountId)
        {
            try
            {
                var today = DateTime.Now.ToString("yyyyMMdd");
                string key = $"pdd_daily_usage:{accountId}:{today}";
                return RedisHelper.Get<int>(key);
            }
            catch (Exception)
            {
                return 0;
            }
        }

        internal static void UpdateAccountUsage(int accountId)
        {
            try
            {
                var today = DateTime.Now.ToString("yyyyMMdd");
                string key = $"pdd_daily_usage:{accountId}:{today}";

                // 递增计数并设置24小时过期时间
                RedisHelper.IncrBy(key);
                RedisHelper.Expire(key, 86400); // 24小时后自动过期
            }
            catch (Exception ex)
            {
                // 记录错误但不影响主流程
                Console.WriteLine($"Failed to update account usage for {accountId}: {ex.Message}");
            }
        }

        /// <summary>
        /// 获取当前所有账号的平均使用次数
        /// </summary>
        private static int GetAverageUsageCount()
        {
            try
            {
                var activeAccounts = List()?.Where(a => a.enable_parse).ToList();
                if (activeAccounts == null || !activeAccounts.Any()) return 0;

                var today = DateTime.Now.ToString("yyyyMMdd");
                var totalUsage = 0;
                var validCount = 0;

                foreach (var account in activeAccounts)
                {
                    var usage = GetCurrentDayUsageFromRedis(account.id);
                    totalUsage += usage;
                    validCount++;
                }

                return validCount > 0 ? totalUsage / validCount : 0;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Failed to get average usage count: {ex.Message}");
                return 0;
            }
        }

        /// <summary>
        /// 重置所有在线账号的当日调用次数Redis计数器
        /// 随机排序账号后，每个账号间隔1递增value
        /// </summary>
        public static int RechargeAllOnlineAccountUsage()
        {
            try
            {
                var onlineAccounts = List()?.Where(a => a.status && a.enable_parse).ToList();
                if (onlineAccounts == null || !onlineAccounts.Any())
                {
                    return 0;
                }

                var today = DateTime.Now.ToString("yyyyMMdd");

                // 随机排序账号
                var random = new Random();
                var shuffledAccounts = onlineAccounts.OrderBy(x => random.Next()).ToList();

                int incrementValue = 1;
                int rechargedCount = 0;

                foreach (var account in shuffledAccounts)
                {
                    string key = $"pdd_daily_usage:{account.id}:{today}";

                    // 设置递增的value并设置24小时过期时间
                    RedisHelper.Set(key, incrementValue, 86400);
                    RedisHelper.Set(key, 0, 86400);
                    incrementValue++;
                    rechargedCount++;
                }
                return rechargedCount;
            }
            catch (Exception ex)
            {
            }
            return 0;
        }

        /// <summary>
        /// 为新上线的账号设置平均使用次数（仅用于降级策略的统计）
        /// 注意：基于时间间隔的调度策略不需要初始化权重，因为无历史记录的账号会自动返回DateTime.MinValue
        /// </summary>
        public static void InitializeNewAccountUsage(int accountId, string groupKey = "default")
        {
            try
            {
                var today = DateTime.Now.ToString("yyyyMMdd");
                string usageKey = $"pdd_daily_usage:{accountId}:{today}";

                // 检查该账号今天是否已有使用记录
                var currentUsage = RedisHelper.Get<int>(usageKey);
                if (currentUsage > 0)
                {
                    Console.WriteLine($"Account {accountId} already has usage record: {currentUsage}, skip initialization");
                    return; // 已有记录，不需要初始化
                }

                // 获取所有在线账号的平均值（仅用于降级策略）
                var activeAccounts = List()?.Where(a => a.status && a.enable_parse && a.id != accountId).ToList();
                if (activeAccounts == null || !activeAccounts.Any())
                {
                    Console.WriteLine($"No other active accounts found, account {accountId} will use default value");
                    return; // 没有其他账号，使用默认值0即可
                }

                // 初始化 daily_usage（用于降级策略的统计）
                var totalUsage = 0;
                foreach (var account in activeAccounts)
                {
                    totalUsage += GetCurrentDayUsageFromRedis(account.id);
                }
                var averageUsage = totalUsage / activeAccounts.Count;
                if (averageUsage > 0)
                {
                    RedisHelper.Set(usageKey, averageUsage, 86400);
                    Console.WriteLine($"Initialized account {accountId} daily_usage with average: {averageUsage}");
                }

                Console.WriteLine($"Account {accountId} initialization complete. Time-based scheduling will use DateTime.MinValue for idle time calculation.");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Failed to initialize new account for {accountId}: {ex.Message}");
            }
        }
        /// <summary>
        /// 获取当前统计信息（用于监控和调试）- 改为从Redis获取
        /// </summary>
        internal static Dictionary<string, int> GetCurrentUsageSnapshot()
        {
            try
            {
                var result = new Dictionary<string, int>();
                var accounts = List()?.Where(a => a.status && a.enable_parse).ToList();
                if (accounts == null || !accounts.Any()) return result;

                var today = DateTime.Now.ToString("yyyyMMdd");
                foreach (var account in accounts)
                {
                    string key = $"pdd_daily_usage:{account.id}:{today}";
                    int usage = RedisHelper.Get<int>(key);
                    result[$"Account_{account.id}_{account.name}"] = usage;
                }

                return result;
            }
            catch (Exception)
            {
                return new Dictionary<string, int>();
            }
        }

        /// <summary>
        /// 获取账号调度时间间隔信息（用于监控和调试）
        /// </summary>
        public static Dictionary<string, object> GetScheduleWeightSnapshot(string groupKey = "default")
        {
            try
            {
                var result = new Dictionary<string, object>();
                var accounts = List()?.Where(a => a.status && a.enable_parse).ToList();
                if (accounts == null || !accounts.Any()) return result;

                var now = DateTime.Now;
                var accountInfos = new List<Dictionary<string, object>>();

                foreach (var account in accounts)
                {
                    var lastUsedTime = GetAccountLastUsedTime(account.id, groupKey);
                    long idleMs = (long)(now - lastUsedTime).TotalMilliseconds;
                    bool canUse = account.cis_limit <= 0 || idleMs >= account.cis_limit;

                    var info = new Dictionary<string, object>
                    {
                        ["account_id"] = account.id,
                        ["account_name"] = account.name,
                        ["cis_limit_ms"] = account.cis_limit,
                        ["last_used_time"] = lastUsedTime == DateTime.MinValue ? "从未使用" : lastUsedTime.ToString("yyyy-MM-dd HH:mm:ss.fff"),
                        ["idle_time_ms"] = idleMs,
                        ["idle_time_seconds"] = Math.Round(idleMs / 1000.0, 2),
                        ["can_use"] = canUse,
                        ["daily_usage"] = GetCurrentDayUsageFromRedis(account.id),
                        ["daily_limit"] = account.daily_calls_limit
                    };
                    accountInfos.Add(info);
                }

                // 按照空闲时间降序排序（与选择逻辑一致）
                accountInfos = accountInfos.OrderByDescending(x => (long)x["idle_time_ms"]).ToList();

                result["accounts"] = accountInfos;
                result["group_key"] = groupKey;
                result["timestamp"] = now.ToString("yyyy-MM-dd HH:mm:ss.fff");
                result["total_accounts"] = accountInfos.Count;
                result["available_accounts"] = accountInfos.Count(x => (bool)x["can_use"]);

                return result;
            }
            catch (Exception ex)
            {
                return new Dictionary<string, object> { ["error"] = ex.Message };
            }
        }

        /// <summary>
        /// 强制清理统计数据（仅用于测试或紧急情况）- Redis版本
        /// </summary>
        internal static void ForceClearStats()
        {
            try
            {
                var today = DateTime.Now.ToString("yyyyMMdd");
                var pattern = $"pdd_daily_usage:*:{today}";

                // TODO: 实现Redis批量删除相关keys
                // 生产环境中需要谨慎使用
                Console.WriteLine("Force clear stats - Redis keys will auto-expire in 24h");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Failed to force clear stats: {ex.Message}");
            }
        }

        internal static void TempSuspend(int accountId)
        {
            _suspend.AddOrUpdate(accountId, DateTime.Now, (key, oldValue) => DateTime.Now);
        }

        private static bool IsMatch(PddPoolDTO item, PddUnionWorkMode mode, int accountid)
        {
            if (accountid != 0 && accountid != item.id) return false;
            if (!item.enable_parse) return false;
            if (mode != PddUnionWorkMode.All && mode != item.work_mode) return false;
            if (item.work_mode == PddUnionWorkMode.Crawler && !item.cookie_status) return false;

            if (!string.IsNullOrEmpty(_end_point) && !string.IsNullOrEmpty(item.end_point))
            {
                if (item.end_point != _end_point) return false;
            }

            // 使用初始化参数创建工作时间表
            if (!new WorkSchedule(item.time_range).IsWorkHour()) return false;

            if (_suspend.TryGetValue(accountid, out DateTime suspendTime))
            {
                var ts = DateTime.Now - suspendTime;
                if (ts.TotalSeconds < 70) return false;
            }

            // cis_limit 检查已移至 SmoothWeightedRoundRobin 方法中基于时间间隔判断
            // 这里不再需要检查 Redis 锁


#if DEBUG
#else
            if (item.rpm_limit > 0)
            {
                int rpm_num = RiskControlCore.GetCalls(TkChannelEnum.pdd, item.id, DateTime.Now.ToString("yyyyMMddHHmm"));
                if (rpm_num >= item.rpm_limit) return false;
            }
            if (item.daily_calls_limit > 0)
            {
                int daily_num = RiskControlCore.GetCalls(TkChannelEnum.pdd, item.id, DateTime.Now.ToString("yyyyMMdd"));
                if (daily_num >= item.daily_calls_limit) return false;
            }
            if (item.hourly_calls_limit > 0)
            {
                int hourly_num = RiskControlCore.GetCalls(TkChannelEnum.pdd, item.id, DateTime.Now.ToString("yyyyMMddHH"));
                if (hourly_num >= item.hourly_calls_limit) return false;
            }
#endif
            return true;
        }



        public static async Task<IEnumerable<PddPoolDTO>> AllListAsync(bool force = false)
        {
            if (!force && _all_cached != default) return _all_cached;

            try
            {
                await _semaphore.WaitAsync();

                string cache_key = $"cache:all_pdd_pool";
                var list = await RedisKit.GetAsync<IEnumerable<PddPoolDTO>>(cache_key);

                if (force || list == default)
                {
                    list = new DBContext.Table("pdd_pool").Select<PddPoolDTO>();
                    if (list == null) return default;

                    // 等待 Redis 写入完成
                    await RedisKit.SetAsync(cache_key, list, 30 * 86400);
                }

                _all_cached = list;
                return list;
            }
            catch (Exception)
            {
                // 发生异常时返回上一次的缓存，如果没有则返回默认值
                return _all_cached ?? default;
            }
            finally
            {
                _semaphore.Release();
            }
        }
        public static IEnumerable<PddPoolDTO> List(bool force = false)
        {
            if (!force && _cached != null) return _cached;

            string cache_key = $"cache:pdd_pool";
            var list = RedisHelper.Get<IEnumerable<PddPoolDTO>>(cache_key);
            if (force || list == null)
            {
                lock (_lockObj)
                {
                    list = new DBContext.Table("pdd_pool")
                        .Where("status=@status", new { status = 1 })
                        .Select<PddPoolDTO>();
                    if (list == null) return default;
                    foreach (var item in list)
                    {
                        RiskControlCore.SetCallsAsync(TkChannelEnum.pdd, item.id, DateTime.Now.ToString("yyyyMMddHH"), item.current_hourly_calls);
                        RiskControlCore.SetCallsAsync(TkChannelEnum.pdd, item.id, DateTime.Now.ToString("yyyyMMdd"), item.current_daily_calls);
                    }
                    RedisHelper.Set(cache_key, list, 30 * 86400);
                }
            }
            _cached = list;
            return list;
        }
        public static void Refresh()
        {
            _cached = null;
            _all_cached = null;
            _ = List(true);
            _ = AllListAsync(true);
        }

        public static void Disabled(string name)
        {
            string cache_key = $"cache:pdd_pool:{name}:disabled";
            long count = RedisHelper.IncrBy(cache_key);
            RedisHelper.Expire(cache_key, 10);
            if (count > 1) return;

            new DBContext.Table("pdd_pool")
                .Add("status", 0)
                .Where("name=@name", new { name })
                .Update();
            _ = List(true);

            NotifyCore.Notify(new NifyMessage
            {
                message = $"【多多:{name}】调用异常",
                priority = NifyMessagePriority.high,
                tags = ["red_circle"]
            });
        }


        public static void Disabled(int accountId, string name, string content)
        {
            string cache_key = $"cache:pdd_pool:{name}:disabled";
            long count = RedisHelper.IncrBy(cache_key);
            RedisHelper.Expire(cache_key, 10);
            if (count > 1) return;

            var update = new DBContext.Table("pdd_pool").Add("status", 0);
            if (accountId > 0)
            {
                update.Where("id=@accountId", new { accountId }).Update();
            }
            else
            {
                update.Where("name=@name", new { name }).Update();
            }

            _ = List(true);

            NotifyCore.Notify(new NifyMessage
            {
                message = $"【多多{accountId}:{name}】cookie 掉线\n\n{content}",
                priority = NifyMessagePriority.high,
                tags = ["red_circle"]
            });

            //NotifyCore.QYWeixinPushNotifyAsync("掉线", $"【多多{accountId}:{name}】cookie 掉线");
            EndPointCore.NotifyReload(true);
        }

        internal static void AccountExhausted()
        {
            string cache_key = $"cache:pdd_pool:account:exhausted";
            long count = RedisHelper.IncrBy(cache_key);
            if (count > 1) return;
            RedisHelper.Expire(cache_key, 3600);
            NotifyCore.Notify(new NifyMessage
            {
                message = $"【多多】没有匹配账号",
                priority = NifyMessagePriority.high,
                tags = ["red_circle"]
            });
            //_ = NotifyCore.QYWeixinPushNotifyAsync("没账号", $"【多多】没有匹配账号");
        }

        internal static async Task<JsonElement> GetUserInfo(string cookies)
        {
            JsonElement result = default;
            try
            {
                string url = "https://jinbao.pinduoduo.com/network/api/account/userInfo";
                WebClientUtility client = new WebClientUtility();
                client.Post("{}");
                client.SetCookies(cookies);
                client.SetContentType("application/json");
                var response = await client.RequestAsync(url, "POST");
                var body = response.Body();
                result = body.Convert2JsonElement();
            }
            catch (Exception ex)
            {
            }
            return result;
        }

        public static async Task<int> UpdateCookies(string cookies, string user_agent, int id = 0)
        {
            if (string.IsNullOrEmpty(cookies)) return 0;
            var userinfo = await GetUserInfo(cookies);
            if (userinfo.ValueKind != JsonValueKind.Object) return 0;

            int duoId = userinfo.PathRead<int>("result.duoId", 0);
            string company = userinfo.PathRead<string>("result.mobile", string.Empty);
            string lastPid = userinfo.PathRead<string>("result.lastPid", string.Empty);

            int accountId = 0;
            if (duoId == 0 && id == 0) return 0;


            string filter = id != 0 ? "id=@id" : "duoId=@duoId";
            var exist = new DBContext.Table("pdd_pool").Get<PddPoolDTO>(filter, new { id, duoId });
            if (exist != null)
            {
                var status = exist.status;
                var work_mode = exist.work_mode;
                accountId = exist.id;
                if (work_mode == PddUnionWorkMode.Crawler) status = true;
                new DBContext.Table("pdd_pool")
                    .Add("cookies", cookies)
                    .Add("user_agent", user_agent)
                    .Add("status", status)
                    .Add("cookie_status", 1)
                    .Add("last_time", DateTime.Now)
                    .Add("login_time", DateTime.Now)
                    .Where("id=@id", new { exist.id })
                    .Update();
                if (status)
                {
                    _ = List(true);
                    // 为重新上线的账号初始化使用次数和权重（针对所有分组）
                    InitializeNewAccountUsage(exist.id, "default");
                    InitializeNewAccountUsage(exist.id, "dp");
                }
            }
            else
            {
                accountId = new DBContext.Table("pdd_pool")
                    .Add("duoId", duoId)
                    .Add("name", company)
                    .Add("company", company)
                    .Add("description", "由cookies上报创建此记录")
                    .Add("cookies", cookies)
                    .Add("user_agent", user_agent)
                    .Add("pid", lastPid)
                    .Add("cookie_status", 1)
                    .Add("create_time", DateTime.Now)
                    .Add("last_time", DateTime.Now)
                    .Add("login_time", DateTime.Now)
                    .Add("status", 0)
                    .Create();

                // 为新创建的账号初始化使用次数（如果将来会启用的话）
                // InitializeNewAccountUsage(accountId); // 暂不调用，因为新创建的账号status=0
            }

            NotifyCore.Notify(new NifyMessage
            {
                message = $"【拼多多{accountId}:{company}】cookie 上线",
                tags = ["green_circle"]
            });
            EndPointCore.NotifyReload(true);
            //NotifyCore.QYWeixinPushNotifyAsync("上线", $"【淘宝联盟:{dnk}】cookie 上报更新");
            return accountId;
        }


        public static int CookieDisabled(int id)
        {
            return new DBContext.Table("pdd_pool")
                .Add("cookie_status", 0)
                .Add("last_time", DateTime.Now)
                .Where("id=@id", new { id })
                .Update();
        }


        public static int Update(PddPoolDTO account)
        {
            return new DBContext.Table("pdd_pool")
                .Add("current_hourly_calls", account.current_hourly_calls)
                .Add("current_daily_calls", account.current_daily_calls)

                //.Add("today_clickNum", account.today_clickNum)
                //.Add("today_cosFee", account.today_cosFee)
                //.Add("today_cosPrice", account.today_cosPrice)
                //.Add("today_finishCosFee", account.today_finishCosFee)
                //.Add("today_finishCosPrice", account.today_finishCosPrice)
                //.Add("today_finishOrderNum", account.today_finishOrderNum)
                //.Add("today_orderNum", account.today_orderNum)
                .Add("last_time", DateTime.Now)
                .Where("id=@id", new { account.id })
                .Update();
        }

        public static void AccountRisk(PddPoolDTO account)
        {
            string cache_key = $"cache:pdd_pool:{account.name}:disabled";
            long count = RedisHelper.IncrBy(cache_key);
            RedisHelper.Expire(cache_key, 10);
            if (count > 1) return;


            // 发送通知
            string message = $"【PDD风控】【{account.id}:{account.name}】出现30007";
            NotifyCore.Notify(new NifyMessage
            {
                message = message,
                priority = NifyMessagePriority.high,
                tags = ["red_circle"]
            });

            if (!account.is_hide)
            {
                _ = NotifyCore.QYWeixinPushNotifyAsync("PDD风控", message);
            }

            // 设置风控标记
            RiskControlCore.SetRiskCookie($"pdd:{account.id}", "30007");

            // 更新数据库状态
            new DBContext.Table("pdd_pool")
            .Add("enable_parse", 0)
                .Where("id=@id", new { account.id })
                .Update();
            _ = List(true);

            _ = EndPointCore.NotifyReload(true);

        }
    }
}
