using dodohold.core;
using System.Collections.Generic;
using System.Data;
using System.Security.Cryptography;
using System.Text.RegularExpressions;
using System.Web;
using YunhuiKit;


namespace molilian.core
{

    public partial class OverrideRuleCore
    {

        private static IEnumerable<OverrideRuleDTO> _cached;

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

        public static async Task<IEnumerable<OverrideRuleDTO>> ListAsync(bool force = false)
        {
#if DEBUG

            return new DBContext.Table("tk_override_rules")
                   .Where("status=@status", new { status = 1 })
                   .Order("sort DESC, id DESC")
                   .Select<OverrideRuleDTO>();
#endif

            if (!force && _cached != null) return _cached;
            try
            {
                await _semaphore.WaitAsync();

                // 如果缓存存在且未强制刷新，直接返回
                if (!force && _cached != null) return _cached;

                string cache_key = $"cache:tk_override_rules";
                IEnumerable<OverrideRuleDTO>? list = null;

                // 尝试从Redis获取数据
                try
                {
                    list = await RedisKit.GetAsync<IEnumerable<OverrideRuleDTO>>(cache_key);
                }
                catch (Exception ex)
                {
                    // 记录Redis错误
                    _ = new LoggerLibrary("OverrideRule", "Redis").Info(ex.Message, ex.StackTrace).SaveAsync();
                }

                // 如果Redis获取失败或需要强制刷新
                if (force || list == null)
                {
                    try
                    {
                        list = new DBContext.Table("tk_override_rules")
                            .Where("status=@status", new { status = 1 })
                            .Order("sort DESC, id DESC")
                            .Select<OverrideRuleDTO>();

                        if (list != null && list.Any())
                        {
                            // 尝试更新Redis缓存
                            try
                            {
                                await RedisKit.SetAsync(cache_key, list, 30 * 86400);
                            }
                            catch (Exception ex)
                            {
                                // 记录Redis更新错误
                                _ = new LoggerLibrary("OverrideRule", "Redis").Info(ex.Message, ex.StackTrace).SaveAsync();
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        // 记录数据库查询错误
                        _ = new LoggerLibrary("OverrideRule", "Database").Info(ex.Message, ex.StackTrace).SaveAsync();

                        // 如果数据库查询失败但缓存还在，继续使用缓存
                        if (_cached != null) return _cached;
                        throw; // 如果没有任何可用数据，则抛出异常
                    }
                }
                _cached = list;
                return list ?? [];
            }
            finally
            {
                _semaphore.Release();
            }
        }

        public static async Task<OverrideRuleDTO> ProcessAsync(UnionParseRequest request)
        {
            if (string.IsNullOrEmpty(request.Channel)) return null;
            var list = await ListAsync();
            if (list == default) return null;
            string content = request.Content;
            if (request.SpecialText == 1) content = request.QueryText;
            if (string.IsNullOrEmpty(content)) return null;

            foreach (var item in list)
            {
                //
                if (!request.Channel.Equals(item.platform)) continue;
                if (item.use_special_text == 1 && request.SpecialText != 1) continue;

                string original_text = item.original_text;
                if (item.use_special_text == 1) original_text = request.QueryText;
                if (string.IsNullOrEmpty(original_text)) continue;

                switch (item.rule)
                {
                    case "regex":
                        Match match = Regex.Match(content, original_text);
                        if (!match.Success) continue;
                        break;
                    case "text":
                        if (!content.Equals(original_text)) continue;
                        break;
                    default:
                        if (!content.Contains(original_text)) continue;
                        break;
                }
                if (item.use_special_text == 1 && request.SpecialText != 1) continue;

                if (item.use_risk_control)
                {
                    bool is_ignore = AlimamaPlus.ShouldIgnoreRequest(request, out _);
                    if (is_ignore) continue;
                    is_ignore = AlimamaPlus.FlowControlIgnoreRequest(request, out _);
                    if (is_ignore) continue;
                }

                // 每小时调用次数统计（无论是否设置限制都要记录）
                string hourlyKey = $":override_rule_calls:{item.id}:{DateTime.Now:yyyyMMddHH}";
                try
                {
                    long currentHourlyCalls = await RedisKit.IncrByAsync(hourlyKey);
                    // 如果是第一次调用，设置过期时间为2小时
                    if (currentHourlyCalls < 10)
                    {
                        await RedisKit.ExpireAsync(hourlyKey, 7200); // 2小时
                    }

                    // 如果设置了每小时限制且超过限制，跳过该规则
                    if (item.hourly_calls_limit > 0 && currentHourlyCalls > item.hourly_calls_limit) continue;
                }
                catch (Exception ex)
                {
                    // Redis错误时记录日志但不阻塞业务
                    _ = new LoggerLibrary("OverrideRule", "Redis").Info($"Hourly limit check failed: {ex.Message}", ex.StackTrace).SaveAsync();
                }

                // 每日调用次数统计（无论是否设置限制都要记录）
                string dailyKey = $":override_rule_calls:{item.id}:{DateTime.Now:yyyyMMdd}";
                try
                {
                    long currentDailyCalls = await RedisKit.IncrByAsync(dailyKey);
                    if (currentDailyCalls < 10)
                    {
                        await RedisKit.ExpireAsync(dailyKey, 259200); // 3天
                    }
                    // 如果设置了每日限制且超过限制，跳过该规则
                    if (item.daily_calls_limit > 0 && currentDailyCalls >= item.daily_calls_limit) continue;
                }
                catch (Exception ex)
                {
                    // Redis错误时记录日志但不阻塞业务
                    _ = new LoggerLibrary("OverrideRule", "Redis").Info($"Daily limit check failed: {ex.Message}", ex.StackTrace).SaveAsync();
                }

                // 关键词统计 - 长期缓存(6个月)用于历史数据分析
                await SaveKeywordStatisticsAsync(item.id, item.platform, original_text);

                string output_text = item.output_text;
                if (output_text.Contains("{url:query_text}")) output_text = output_text.Replace("{url:query_text}", HttpUtility.UrlEncode(original_text));
                if (output_text.Contains("{url2:query_text}")) output_text = output_text.Replace("{url2:query_text}", HttpUtility.UrlEncode(HttpUtility.UrlEncode(original_text)));
                if (output_text.Contains("{url3:query_text}")) output_text = output_text.Replace("{url3:query_text}", HttpUtility.UrlEncode(HttpUtility.UrlEncode(HttpUtility.UrlEncode(original_text))));
                if (output_text.Contains("{query_text}")) output_text = output_text.Replace("{query_text}", original_text);
                item.output_text = output_text;
                return item;
            }
            return null;
        }

        /// <summary>
        /// 保存关键词统计数据到Redis，用于长期数据分析
        /// 缓存周期：6个月
        /// </summary>
        private static async Task SaveKeywordStatisticsAsync(int ruleId, string platform, string keyword)
        {
            try
            {
                // 6个月的秒数
                const int sixMonthsInSeconds = 180 * 86400;

                // 关键词总请求次数统计 - 按月份
                string monthlyKey = $":keyword_stats:{platform}:{ruleId}:{DateTime.Now:yyyyMM}";
                await RedisKit.IncrByAsync(monthlyKey);
                await RedisKit.ExpireAsync(monthlyKey, sixMonthsInSeconds);

                // 关键词总请求次数统计 - 按日
                string dailyKey = $":keyword_stats:{platform}:{ruleId}:{DateTime.Now:yyyyMMdd}";
                await RedisKit.IncrByAsync(dailyKey);
                await RedisKit.ExpireAsync(dailyKey, sixMonthsInSeconds);

                // 关键词总请求次数统计 - 按小时
                string hourlyKey = $":keyword_stats:{platform}:{ruleId}:{DateTime.Now:yyyyMMddHH}";
                await RedisKit.IncrByAsync(hourlyKey);
                await RedisKit.ExpireAsync(hourlyKey, sixMonthsInSeconds);

                // 平台维度统计
                string platformMonthlyKey = $":keyword_stats:platform:{platform}:{DateTime.Now:yyyyMM}";
                await RedisKit.IncrByAsync(platformMonthlyKey);
                await RedisKit.ExpireAsync(platformMonthlyKey, sixMonthsInSeconds);

                // 全局统计
                string globalMonthlyKey = $":keyword_stats:global:{DateTime.Now:yyyyMM}";
                await RedisKit.IncrByAsync(globalMonthlyKey);
                await RedisKit.ExpireAsync(globalMonthlyKey, sixMonthsInSeconds);

                // 记录关键词集合（用于后续查询有哪些关键词）
                string keywordSetKey = $":keyword_stats:set:{platform}:{DateTime.Now:yyyyMM}";
                await RedisKit.SAddAsync(keywordSetKey, keyword);
                await RedisKit.ExpireAsync(keywordSetKey, sixMonthsInSeconds);
            }
            catch (Exception ex)
            {
                // Redis错误时记录日志但不阻塞业务
                _ = new LoggerLibrary("OverrideRule", "KeywordStats").Info($"Keyword statistics save failed: {ex.Message}", ex.StackTrace).SaveAsync();
            }
        }

        public static void Refresh()
        {
            _cached = null;
            _ = ListAsync(true);
        }


        public static int Update(OverrideRuleDTO data, IDbConnection conn)
        {
            var result = (int)conn.Update<OverrideRuleDTO>(data, new { data.id });
            _ = ListAsync(true);
#if DEBUG
#else
            EndPointCore.NotifyReload();
#endif
            return result;
        }

        public static int Create(OverrideRuleDTO data, IDbConnection conn)
        {
            var result = (int)conn.Insert(data);
            _ = ListAsync(true);
#if DEBUG
#else
            EndPointCore.NotifyReload();
#endif
            return result;
        }


    }
}
