
using dodohold.core;
using Microsoft.AspNetCore.Mvc;
using Sayaka.Common;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Web;
namespace molilian.core
{
    public partial class DeeplinkParseCore
    {


        private static string _end_point;
        private static readonly string[] separators = ["\r\n", "\n"];

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


        public static DeeplinkParseDataDTO GetFormattedObject(UnionParseRequest request)
        {
            return new DeeplinkParseDataDTO()
            {
                message = string.Empty,
                success = false,
                content = request.Content,
                ip = request.Ip,
                oaid = request.Oaid,
                elapsedTime = 0,
                create_time = DateTime.Now,
                end_point = _end_point,
            };
        }

        public static async Task<ActionResult> ParseAsync(UnionParseRequest request)
        {
            var result = GetFormattedObject(request);
            request.Content = request.Content.Trim();

            var rule = DeeplinkParseRuleCore.GetOne(request.Channel);
            if (rule == null)
            {
                result.success = false;
                result.message = "转链失败";
                result.reason = "无效平台";

                _ = TkLogCore.ParseLogAsync(result);
                return new APIResult(new
                {
                    result.success,
                    result.message,
                    result.reason,
                });
            }

            result.channel_id = rule.channel_id;
            result.channel_name = rule.channel_name;


            var overrideContent = await OverrideRuleCore.ProcessAsync(request);
            if (overrideContent != null)
            {
                result.success = true;
                result.message = "OK";
                result.deeplink_url = overrideContent.output_text;

                _ = TkLogCore.ParseLogAsync(result);
                return new APIResult(new
                {
                    result.success,
                    result.message,
                    channel = result.channel_name,
                    result.deeplink_url
                });
            }



            if (ShouldIgnoreRequest(rule.IgnorePercentageCity, request.Ip, request.Oaid, out string reason))
            {
                result.success = false;
                result.message = "放弃转链";
                result.reason = reason;

                _ = TkLogCore.ParseLogAsync(result);
                return new APIResult(new
                {
                    result.success,
                    result.message,
                    result.reason,
                });
            }
            result = await GenerateDeeplink(request.Content, rule, result);

            _ = TkLogCore.ParseLogAsync(result);
            return new APIResult(new
            {
                result.success,
                result.message,
                channel = result.channel_name,
                result.deeplink_url,
                result.itemName,
            });
        }

        public static bool ShouldIgnoreRequest(string ignorePercentageCity, string ip, string oaid, out string reason)
        {
            reason = string.Empty;
            try
            {
                // IP和流量控制
                string? ipInfo = IP2RegionPlus.Search(ip);
                if (!TestParseCore.InWhitelist(ip, oaid) && AlimamaPlus.IgnoreRegionIncluded(ignorePercentageCity, ipInfo, out string regionInfo))
                {
                    reason = $"地区控制：{regionInfo}";
                    return true;
                }
            }
            catch (Exception ex)
            {
                reason = "配置异常";
            }
            return false;
        }




        public static async Task<DeeplinkParseDataDTO> GenerateDeeplink(string text, DeeplinkParseRuleDTO config, DeeplinkParseDataDTO result)
        {
            try
            {
                var list = config.rules.Convert2Object<List<DeeplinkParseRule>>();

                foreach (var rule in list)
                {
                    var e = await WorkEachRule(text, config, result, rule);
                    if (e != null) return e;
                }
            }
            catch (Exception ex)
            {
            }

            result.success = false;
            return result;
        }

        private static async Task<DeeplinkParseDataDTO?> WorkEachRule(string text, DeeplinkParseRuleDTO config, DeeplinkParseDataDTO result, DeeplinkParseRule rule)
        {
            if (!rule.enable) return null;

            string content = text;

            if (!string.IsNullOrEmpty(rule.url_pattern))
            {
                var regex = new Regex(rule.url_pattern);
                var match = regex.Match(content);
                if (!match.Success) return null;

                content = match.Groups[1].Value;
            }

            string url = ToolParsePlus.GetLink(text);
            try
            {
                switch (rule.url_action)
                {
                    case UrlAction.Redirect:
                        {
                            var response = await new WebClientUtility
                            {
                                Proxy = ProxyNodesCore.RandomOne(),
                                UserAgent = ProviderFakeUserAgent.RandomMobile,
                                AllowAutoRedirect = false
                            }.RequestAsync(url);
                            if (response.ResponseMessage != null)
                            {
                                content = response.ResponseMessage.Headers.Location.ToString();
                                //content = content.UrlDecode();
                            }
                            if (string.IsNullOrEmpty(content)) return null;
                        }
                        break;
                    case UrlAction.Body:
                    case UrlAction.JsonBody:
                        {
                            var client = new WebClientUtility
                            {
                                Proxy = ProxyNodesCore.RandomOne(),
                                UserAgent = ProviderFakeUserAgent.RandomMobile,
                                AllowAutoRedirect = true
                            };
                            if (!string.IsNullOrEmpty(rule.post))
                            {
                                string postData = rule.post;
                                // 使用现有占位符处理逻辑
                                if (!string.IsNullOrEmpty(rule.url_pattern))
                                {
                                    var urlRegex = new Regex(rule.url_pattern);
                                    var urlMatch = urlRegex.Match(text);
                                    if (urlMatch.Success)
                                    {
                                        for (var i = 1; i < urlMatch.Groups.Count; i++)
                                        {
                                            string val = urlMatch.Groups[i].Value;
                                            string tempPrompt = string.Empty;
                                            ReplaceProcessing(val, i, rule.replacements, ref postData, ref tempPrompt);
                                        }
                                    }
                                }
                                client.Post(postData);
                            }
                            //https://weitoutiao.zjurl.cn/tt_living/?app=news_article&module_name=Android_tt_url&room_id=MDUEDEq2rcgYaV8/SarVCgQTTv3vQwSt/yRnpWHHMzSd1LxjfgQQXTdEOrBDTfdJCzQ+vyO1aQ==&share_did=MS4wLjACAAAASvJER5nlmrwCRfsC2t661YpMGJbq2HtGQS31wppWCCm_j6e1qZ7w9bp94n9T6Ouq&share_token=99222dee-be68-4f79-af9e-c32eff162ea8&share_uid=MS4wLjABAAAA9PBhcsrMuvXb3-0VPXN47TT4TKDHqiZR-LCS4B2BodaRdd7OHm7rl1Xx3SxlLrbn&timestamp=1756194703&tt_from=copy_link&upstream_biz=client_share&utm_campaign=client_share&utm_medium=toutiao_android&utm_source=copy_link
                            //https://weitoutiao.zjurl.cn/tt_living/?app=news_article&module_name=Android_tt_url&room_id=MDUEDEq2rcgYaV8%2FSarVCgQTTv3vQwSt%2FyRnpWHHMzSd1LxjfgQQXTdEOrBDTfdJCzQ%2BvyO1aQ%3D%3D&share_did=MS4wLjACAAAASvJER5nlmrwCRfsC2t661YpMGJbq2HtGQS31wppWCCm_j6e1qZ7w9bp94n9T6Ouq&share_token=99222dee-be68-4f79-af9e-c32eff162ea8&share_uid=MS4wLjABAAAA9PBhcsrMuvXb3-0VPXN47TT4TKDHqiZR-LCS4B2BodaRdd7OHm7rl1Xx3SxlLrbn&timestamp=1756194703&tt_from=copy_link&upstream_biz=client_share&utm_campaign=client_share&utm_medium=toutiao_android&utm_source=copy_link


                            var response = await client.RequestAsync(url);

                            content = response.Body();
                            if (string.IsNullOrEmpty(content)) return null;

                        }
                        break;
                    case UrlAction.None:
                        //{
                        //    content = url;
                        //}
                        break;
                }
            }
            catch (Exception ex)
            {
                //Console.WriteLine($"{url}\t{rule.url_action}\t{ex.Message}");
            }
            if (!string.IsNullOrEmpty(rule.slice_pattern))
            {
                var regex = new Regex(rule.slice_pattern);
                var match = regex.Match(content);
                if (!match.Success) return null;
                content = match.Groups[1].Value;
            }

            if (rule.childs.Count > 0)
            {
                foreach (var sub_rule in rule.childs)
                {
                    var e = await WorkEachRule(content, config, result, sub_rule);
                    if (e != null) return e;
                }
                return null;
            }



            if (!string.IsNullOrEmpty(rule.body_pattern))
            {
                var regex = new Regex(rule.body_pattern);
                var match = regex.Match(content);
                if (!match.Success) return null;

            }

            var deeplink = rule.deeplink_template;
            var prompt_text = rule.prompt_text;

            try
            {
                var regex = new Regex(rule.pattern);
                var match = regex.Match(content);
                if (match.Success)
                {

                    if (rule.resources.Count > 0)
                    {
                        foreach (var resource in rule.resources)
                        {
                            Dictionary<string, string> resResult = await ResourceProcessing(match, resource, rule.replacements);
                            foreach (var e in resResult)
                            {
                                if (deeplink.Contains(e.Key))
                                {
                                    deeplink = deeplink.Replace(e.Key, e.Value);
                                }
                            }
                        }
                    }

                    if (match.Groups.Count > 1)
                    {

                        for (var i = 1; i < match.Groups.Count; i++)
                        {
                            string val = match.Groups[i].Value;
                            switch (rule.plugin)
                            {
                                case "redu":
                                    string deeplink_url = await PluginDyParseAsync(text, val, result);

                                    if (!string.IsNullOrEmpty(deeplink_url))
                                    {
                                        result.itemName = prompt_text;
                                        result.deeplink_url = deeplink_url;
                                        result.success = true;
                                        return result;
                                    }
                                    break;
                            }
                            ReplaceProcessing(val, i, rule.replacements, ref deeplink, ref prompt_text);
                        }

                        if (rule.replace != null && rule.replace.Count > 0)
                        {
                            foreach (var r in rule.replace)
                            {
                                string key = r[0];
                                if (string.IsNullOrEmpty(key)) continue;

                                string val = string.Empty;
                                if (r.Length > 1)
                                {
                                    val = r[1];
                                }
                                deeplink = Regex.Replace(deeplink, key, val);
                            }
                        }

                        deeplink = Regex.Replace(deeplink, @"\{\d+\}", string.Empty);
                        prompt_text = Regex.Replace(prompt_text, @"\{\d+\}", string.Empty);

                        if (!string.IsNullOrEmpty(deeplink))
                        {
                            result.deeplink_url = deeplink;
                            result.itemName = prompt_text;
                            result.success = true;
                            return result;
                        }
                    }
                    else
                    {
                        result.deeplink_url = deeplink;
                        result.itemName = prompt_text;
                        result.success = true;
                        return result;

                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error processing pattern '{rule.pattern}': {ex.Message}");
            }

            return null;
        }

        /// <summary>
        /// 占位符的处理
        /// </summary>
        /// <param name="word"></param>
        /// <param name="i"></param>
        /// <param name="deeplink"></param>
        /// <param name="prompt_text"></param>
        private static void ReplaceProcessing(string word, int i, List<ReplacementRule> replacements, ref string deeplink, ref string prompt_text)
        {
            if (deeplink.Contains("{url:"))
            {
                string encodedUrl = HttpUtility.UrlEncode(word);
                deeplink = deeplink.Replace($"{{url:{i - 1}}}", encodedUrl);
            }
            if (prompt_text.Contains("{url:"))
            {
                string encodedUrl = HttpUtility.UrlEncode(word);
                prompt_text = prompt_text.Replace($"{{url:{i - 1}}}", encodedUrl);
            }

            if (deeplink.Contains("{decode:"))
            {
                string encodedUrl = HttpUtility.UrlDecode(word);
                deeplink = deeplink.Replace($"{{decode:{i - 1}}}", encodedUrl);
            }
            if (prompt_text.Contains("{decode:"))
            {
                string encodedUrl = HttpUtility.UrlDecode(word);
                prompt_text = prompt_text.Replace($"{{decode:{i - 1}}}", encodedUrl);
            }

            //两次url编码
            if (deeplink.Contains("{url2:"))
            {
                string encodedUrl = HttpUtility.UrlEncode(word);
                encodedUrl = HttpUtility.UrlEncode(encodedUrl);
                deeplink = deeplink.Replace($"{{url2:{i - 1}}}", encodedUrl);
            }
            if (prompt_text.Contains("{url2:"))
            {
                string encodedUrl = HttpUtility.UrlEncode(word);
                encodedUrl = HttpUtility.UrlEncode(encodedUrl);
                prompt_text = prompt_text.Replace($"{{url2:{i - 1}}}", encodedUrl);
            }


            //三次url解码
            if (deeplink.Contains("{url3:"))
            {
                string encodedUrl = HttpUtility.UrlEncode(word);
                encodedUrl = HttpUtility.UrlEncode(encodedUrl);
                deeplink = deeplink.Replace($"{{url3:{i - 1}}}", encodedUrl);
            }
            if (prompt_text.Contains("{url3:"))
            {
                string encodedUrl = HttpUtility.UrlEncode(word);
                encodedUrl = HttpUtility.UrlEncode(encodedUrl);
                prompt_text = prompt_text.Replace($"{{url3:{i - 1}}}", encodedUrl);
            }

            //atob
            if (deeplink.Contains("{atob:"))
            {
                string encodedUrl = HttpUtility.UrlDecode(word);
                deeplink = deeplink.Replace($"{{atob:{i - 1}}}", encodedUrl.FromBase64());
            }
            if (prompt_text.Contains("{atob:"))
            {
                string encodedUrl = HttpUtility.UrlDecode(word);
                prompt_text = prompt_text.Replace($"{{atob:{i - 1}}}", encodedUrl.FromBase64());
            }

            //btoa
            if (deeplink.Contains("{btoa:"))
            {
                string encodedUrl = HttpUtility.UrlEncode(word);
                deeplink = deeplink.Replace($"{{btoa:{i - 1}}}", word.ToBase64());
            }
            if (prompt_text.Contains("{btoa:"))
            {
                string encodedUrl = HttpUtility.UrlEncode(word);
                prompt_text = prompt_text.Replace($"{{btoa:{i - 1}}}", word.ToBase64());
            }
            deeplink = deeplink.Replace($"{{{i - 1}}}", word);
            prompt_text = prompt_text.Replace($"{{{i - 1}}}", word);


            // 新增 <<>> 格式处理
            if (replacements != null)
            {
                deeplink = Regex.Replace(deeplink, @"<<(\w+):([^>]+)>>", match =>
                {
                    var ruleName = match.Groups[1].Value;
                    var value = match.Groups[2].Value;

                    // 查找并应用替换规则
                    var rule = replacements.FirstOrDefault(r => r.Name == ruleName);
                    if (rule != null)
                    {
                        foreach (var r in rule.Rules)
                        {
                            if (r.When.Evaluate(value))
                            {
                                return r.Then;
                            }
                        }
                        return rule.Default;
                    }
                    return value;
                });

                prompt_text = Regex.Replace(prompt_text, @"<<(\w+):([^>]+)>>", match =>
                {
                    var ruleName = match.Groups[1].Value;
                    var value = match.Groups[2].Value;

                    // 查找并应用替换规则
                    var rule = replacements.FirstOrDefault(r => r.Name == ruleName);
                    if (rule != null)
                    {
                        foreach (var r in rule.Rules)
                        {
                            if (r.When.Evaluate(value))
                            {
                                return r.Then;
                            }
                        }
                        return rule.Default;
                    }
                    return value;
                });
            }

            // 最后处理普通的索引替换
            deeplink = deeplink.Replace($"{{{i - 1}}}", word);
            prompt_text = prompt_text.Replace($"{{{i - 1}}}", word);
        }

        private static async Task<Dictionary<string, string>> ResourceProcessing(Match baseMatch, DeeplinkResources resource, List<ReplacementRule> replacements)
        {
            Dictionary<string, string> result = new Dictionary<string, string>();
            string url = resource.url_pattern;
            string prompt_text = string.Empty;
            for (var i = 1; i < baseMatch.Groups.Count; i++)
            {
                string val = baseMatch.Groups[i].Value;
                ReplaceProcessing(val, i, replacements, ref url, ref prompt_text);
            }

            string content = string.Empty;
            try
            {
                switch (resource.url_action)
                {
                    case UrlAction.Redirect:
                        {
                            var response = await new WebClientUtility
                            {
                                Proxy = ProxyNodesCore.RandomOne(),
                                UserAgent = ProviderFakeUserAgent.RandomMobile,
                                AllowAutoRedirect = false
                            }.RequestAsync(url);
                            if (response.ResponseMessage != null)
                            {
                                content = response.ResponseMessage.Headers.Location.ToString();
                                content = content.UrlDecode();
                            }
                        }
                        break;
                    case UrlAction.Body:
                    case UrlAction.JsonBody:
                        {
                            //var response = await new WebClientUtility
                            //{
                            //    Proxy = ProxyNodesCore.RandomOne(),
                            //    UserAgent = ProviderFakeUserAgent.RandomMobile,
                            //    AllowAutoRedirect = true
                            //}.RequestAsync(url);

                            var client = new WebClientUtility
                            {
                                Proxy = ProxyNodesCore.RandomOne(),
                                UserAgent = ProviderFakeUserAgent.RandomMobile,
                                AllowAutoRedirect = true
                            };
                            if (!string.IsNullOrEmpty(resource.post))
                            {
                                string postData = resource.post;
                                // 处理POST数据中的占位符
                                for (var i = 1; i < baseMatch.Groups.Count; i++)
                                {
                                    string val = baseMatch.Groups[i].Value;
                                    ReplaceProcessing(val, i, replacements, ref postData, ref prompt_text);
                                }
                                client.Post(postData);
                            }
                            var response = await client.RequestAsync(url);
                            content = response.Body();
                        }
                        break;
                    case UrlAction.None:
                        //{
                        //    content = url;
                        //}
                        break;
                }
            }
            catch (Exception ex)
            {
                //Console.WriteLine($"{url}\t{rule.url_action}\t{ex.Message}");
            }

            if (string.IsNullOrEmpty(content)) { return result; }


            try
            {
                JsonElement root = default;
                if (UrlAction.JsonBody.Equals(resource.url_action))
                {
                    root = content.Convert2JsonElement();
                }

                for (int i = 0; i < resource.pattern.Count; i++)
                {
                    string val = string.Empty;

                    if (UrlAction.JsonBody.Equals(resource.url_action))
                    {
                        val = root.PathRead(resource.pattern[i], string.Empty);
                    }
                    else
                    {
                        var regex = new Regex(resource.pattern[i]);
                        var match = regex.Match(content);
                        if (match.Success)
                        {
                            val = match.Groups[1].Value;
                        }
                    }

                    string key = $"{{{i}@{resource.name}}}";
                    result.Add(key, val);
                }
            }
            catch (Exception ex) { }
            return result;
        }

        public static async Task<string> PluginDyParseAsync(string content, string matchText, DeeplinkParseDataDTO deeplinkResult, CancellationToken cancellationToken = default)
        {
            string ip = deeplinkResult.ip;
            string oaid = deeplinkResult.oaid;

            var result = DyUnionPlus.GetFormattedObject(content, ip, oaid);
            result.create_time = deeplinkResult.create_time;


            result.rawContent = content;
            bool IfExceptional = false;
            try
            {

                if (DyUnionPlus.ShouldIgnoreRequest(ip, oaid, out string reason))
                {
                    result.success = false;
                    result.message = "放弃转链";
                    result.reason = reason;
                    _ = TkLogCore.ParseLogAsync(result);
                    return null;
                }

                var account = ReduPoolCore.GetOne();
                if (account == null)
                {
                    result.success = false;
                    result.message = "放弃转链";
                    result.reason = "没有匹配账号";
                    _ = TkLogCore.ParseLogAsync(result);
                    return null;
                }

                var now = DateTime.Now;
                var ts2 = now - result.create_time;
                result.elapsedTime2 = (int)ts2.TotalMilliseconds;
                result = await DyUnionPlus.DyParseAsync(account, matchText, result, cancellationToken);
                switch (oaid)
                {
                    case "3B191CFA4C6B48F9BA459E915B57743BEC7D424979CC9C51BCAD0C245B1C7BA2":
                    case "6D5D56F3073844F2912B4552CEDF9E3BEC7D424979CC9C51C5461106F1915660":
                    case "4CA55979100C4B5BAAA2AF4ABE15C360602e915cedae5786405419ccc9f4e3f8":
                        break;
                    default:
                        result.deeplink_url = result.deeplink_url.Replace("snssdk1128://", "snssdk561124://");
                        break;
                }

                var ts3 = DateTime.Now - now;
                result.elapsedTime3 = (int)ts3.TotalMilliseconds;
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("was canceled"))
                {
                    result.success = false;
                    result.message = "放弃转链";
                    result.reason = "请求超时";
                }
                else
                {
                    IfExceptional = true;
                    _ = new LoggerLibrary("unionParse", "dy_error")
                        .Info(ip, oaid)
                        .Info(content)
                        .Info(ex.Message, ex.StackTrace)
                        .SaveAsync();
                    NotifyCore.Notify(new NifyMessage
                    {
                        message = $"【转链异常DY】\n{content}\n\n{ex.Message}\n{ex.StackTrace}",
                        priority = NifyMessagePriority.high,
                        tags = ["red_circle"]
                    });
                    result.success = false;
                    result.message = "内部错误";
                    result.reason = "转链接口异常";
                }
            }
            _ = TkLogCore.ParseLogAsync(result);
            return result.deeplink_url;
        }

    }
}
