using dodohold.core;
using Sayaka.Common;
using System.Diagnostics;
using System.Text.RegularExpressions;
using System.Threading.Channels;
using System.Web;

namespace molilian.core
{
    public enum RrecheckGoodsIdResult
    {
        Success,
        Empty,
        Exception,
        InvalidLink,
        OtherAff,
    }

    public partial class PddUnionPlus
    {
        private static readonly object _precheckCircuitLock = new();
        private static bool _precheckDisabled = false;
        private static int _precheckConsecutiveExceptionCount = 0;
        private static int _precheckDisableErrorThreshold = 10;
        public static string _url_pattern = @"https?://(?:[\w-]+\.)*(?:yangkeduo\.com|pinduoduo\.com)(?:/[^\s]*)?";
        public static string GetLink(string content)
        {
            if (string.IsNullOrEmpty(content)) return content;
            string result = content;
            //
            Regex regex = new(_url_pattern);
            MatchCollection matches = regex.Matches(content);

            foreach (Match m in matches.Cast<Match>())
            {
                string url = m.Value;
                return url;
            }
            return string.Empty;
        }


        public static string GetDeeplink(string url)
        {
            string result = $"pinduoduo://com.xunmeng.pinduoduo/{url}";
            return result;
        }

        private static bool IsGoodsDetailPath(string path)
        {
            if (string.IsNullOrWhiteSpace(path)) return false;
            return Regex.IsMatch(path, @"^/goods\d*\.html$", RegexOptions.IgnoreCase);
        }

        private static bool IsPddShortLinkHost(string host)
        {
            return "p.pinduoduo.com".Equals(host, StringComparison.OrdinalIgnoreCase);
        }

        private static bool TryGetPrecheckPsGoodsUrl(string url, out string normalizedUrl)
        {
            normalizedUrl = string.Empty;
            if (string.IsNullOrWhiteSpace(url)) return false;
            if (!Uri.TryCreate(url, UriKind.Absolute, out var uri)) return false;

            if (IsPddShortLinkHost(uri.Host) && !string.IsNullOrWhiteSpace(uri.AbsolutePath) && uri.AbsolutePath != "/")
            {
                normalizedUrl = $"{uri.Scheme}://{uri.Host}{uri.PathAndQuery}";
                return true;
            }

            if (!IsGoodsDetailPath(uri.AbsolutePath)) return false;

            var queryParams = HttpUtility.ParseQueryString(uri.Query);
            string goodsId = queryParams["goods_id"];
            if (!string.IsNullOrWhiteSpace(goodsId) && long.TryParse(goodsId, out _))
            {
                return false;
            }

            string ps = queryParams["ps"];
            if (string.IsNullOrWhiteSpace(ps)) return false;

            normalizedUrl = $"{uri.Scheme}://{uri.Host}{uri.AbsolutePath}?ps={HttpUtility.UrlEncode(ps)}";
            return true;
        }

        private static bool IsPrecheckDisabled()
        {
            lock (_precheckCircuitLock)
            {
                return _precheckDisabled;
            }
        }

        private static void ResetPrecheckExceptionState()
        {
            lock (_precheckCircuitLock)
            {
                _precheckConsecutiveExceptionCount = 0;
            }
        }

        public static void ResetPrecheckCircuitState()
        {
            lock (_precheckCircuitLock)
            {
                _precheckDisabled = false;
                _precheckConsecutiveExceptionCount = 0;
            }
        }

        private static (int count, bool disabledNow) RegisterPrecheckException()
        {
            lock (_precheckCircuitLock)
            {
                _precheckConsecutiveExceptionCount++;
                bool disabledNow = false;
                if (!_precheckDisabled && _precheckConsecutiveExceptionCount >= _precheckDisableErrorThreshold)
                {
                    _precheckDisabled = true;
                    disabledNow = true;
                }
                return (_precheckConsecutiveExceptionCount, disabledNow);
            }
        }

        private static void NotifyPrecheckException(string goodsUrl, string stage, string detail, int count, bool disabledNow)
        {
            string message = $"【PDD商品Precheck异常】{_end_point}\n" +
                $"url:{goodsUrl}\n" +
                $"stage:{stage}\n" +
                $"连续异常:{count}/{_precheckDisableErrorThreshold}\n" +
                $"{detail}";

            if (disabledNow)
            {
                message += "\n状态: 已临时禁用Precheck，后续默认返回Success";
            }

            NotifyCore.Notify(new NifyMessage
            {
                message = message,
                priority = NifyMessagePriority.high,
                tags = ["red_circle"]
            });
        }



        private string ExtractGoodsIdUrl(string url)
        {
            var uri = new Uri(url);
            var queryParams = HttpUtility.ParseQueryString(uri.Query);
            string goodsId = queryParams["goods_id"];

            if (!string.IsNullOrEmpty(goodsId) && uri.AbsolutePath.StartsWith("/goods"))
            {
                // 保持域名和路径不变，仅保留 goods_id 参数
                var baseUrl = $"{uri.Scheme}://{uri.Host}{uri.AbsolutePath}";
                return $"{baseUrl}?goods_id={goodsId}";
            }
            return url; // 如果没有找到 goods_id 参数，则返回原始 URL
        }



        private bool IsTrackUrl(string sourceUrl)
        {
            string pattern = @"^https?://mobile\.yangkeduo\.com/goods(\d*)\.html\?ps=.*$";
            Regex regex = new Regex(pattern);
            return regex.IsMatch(sourceUrl);

        }

        /// <summary>
        /// bool:是否ps链接，string 处理后的链接
        /// </summary>
        /// <param name="sourceUrl"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task<string> GetRedirectedUrlAsync(string sourceUrl, CancellationToken cancellationToken = default)
        {
            var isTrackUrl = IsTrackUrl(sourceUrl);
            if (!isTrackUrl) return ExtractGoodsIdUrl(sourceUrl);
            string redirectedUrl = sourceUrl;

            try
            {
                string useragent = ProviderFakeUserAgent.RandomMobile;
                WebClientUtility client = new()
                {
                    AllowAutoRedirect = false,
                    UserAgent = useragent,
                };
                client.Proxy = _proxy;
#if DEBUG
                client.Proxy = null;
#endif
                var response = await client.RequestAsync(sourceUrl, "GET", cancellationToken);
                if (!response.Successed) return null;

                if (response.ResponseMessage.StatusCode == System.Net.HttpStatusCode.RedirectKeepVerb ||
                  response.ResponseMessage.StatusCode == System.Net.HttpStatusCode.TemporaryRedirect)
                {
                    redirectedUrl = response.ResponseMessage.Headers.Location.ToString();
                    redirectedUrl = ExtractGoodsIdUrl(redirectedUrl);
                    return redirectedUrl;
                }
            }
            catch (Exception ex)
            {
            }
            return sourceUrl;
        }



        public static PddDataDTO GetFormattedObject(UnionParseRequest request)
        {
            switch (request.RiskStrategy)
            {
                case "icon":
                case "tbpush":
                    if (AlimamaPlus.IsDigitsOnly(request.Content))
                    {
                        request.Content = $"https://mobile.yangkeduo.com/goods.html?goods_id={request.Content}";
                    }
                    break;
            }

            string shortLinkurl = GetLink(request.Content);
            string deeplink_url = GetDeeplink(shortLinkurl);
            var link_type = LinkTypeEnum.unknown;
            if (!string.IsNullOrEmpty(shortLinkurl) && shortLinkurl.StartsWith("https://p.pinduoduo.com/"))
            {
                link_type = LinkTypeEnum.other_aff;
            }

            return new PddDataDTO()
            {
                message = string.Empty,
                link_type = link_type,
                channel = TkChannelEnum.pdd,
                accountName = string.Empty,
                success = false,
                content = request.Content,
                ip = request.Ip,
                oaid = request.Oaid,
                elapsedTime = 0,
                itemName = "点击打开拼多多APP",
                shortLinkurl = shortLinkurl,
                deeplink_url = string.Empty,
                create_time = DateTime.Now,
                end_point = _end_point,
                parse_type = request.Type,
                riskStrategy = request.RiskStrategy,
                launchScene = request.LaunchScene,
            };
        }


        public static async Task<RrecheckGoodsIdResult> PrecheckGoodsIdAsync(string content, CancellationToken cancellationToken = default)
        {
            var config = TkConfigCore.Get();
            if (config != null && !config.pdd_rrecheck_enabled)
            {
                return RrecheckGoodsIdResult.Success;
            }

            string url = GetLink(content);
            if (string.IsNullOrEmpty(url))
            {
                return RrecheckGoodsIdResult.InvalidLink;
            }

            if (!TryGetPrecheckPsGoodsUrl(url, out string goods_url))
            {
                return RrecheckGoodsIdResult.Success;
            }



            if (IsPrecheckDisabled()) return RrecheckGoodsIdResult.Success;
            if (string.IsNullOrWhiteSpace(goods_url)) return RrecheckGoodsIdResult.Empty;
            try
            {
                string precheckClientId = config?.pdd_precheck_client_id;
                string precheckClientSecret = config?.pdd_precheck_client_secret;
                string precheckPid = config?.pdd_precheck_pid;

                if (string.IsNullOrWhiteSpace(precheckClientId) || string.IsNullOrWhiteSpace(precheckClientSecret) || string.IsNullOrWhiteSpace(precheckPid))
                {
                    _ = new LoggerLibrary("PddUnion", "PrecheckGoodsIdAsync.Config")
                        .Info(goods_url, "precheck config missing")
                        .SaveAsync();
                    var status = RegisterPrecheckException();
                    NotifyPrecheckException(goods_url, "Config", "precheck config missing", status.count, status.disabledNow);
                    return status.disabledNow ? RrecheckGoodsIdResult.Success : RrecheckGoodsIdResult.Exception;
                }

                var precheckAccount = new PddPoolDTO
                {
                    app_key = precheckClientId,
                    app_secret = precheckClientSecret
                };
                var ts = DateTime.Now.Convert2UnixTimestamp(true);
                var args = new Dictionary<string, string>
                {
                    { "type", "pdd.ddk.goods.search" },
                    { "data_type", "JSON" },
                    { "client_id", precheckClientId },
                    { "keyword", goods_url.UrlDecode() },
                    { "pid", precheckPid },
                    { "timestamp", ts.ToString() }
                };
                args = GenerateSignature(precheckAccount, args);

                var query = HttpUtility.ParseQueryString(string.Empty);
                foreach (var kvp in args) query[kvp.Key] = kvp.Value;
                string urlWithQuery = $"{_baseUrl}?{query}";

                WebClientUtility client = new();
                client.SetContentType("application/json");
                var response = await client.RequestAsync(urlWithQuery, "GET", cancellationToken);
                string body = response.Body();

                if (!response.Successed)
                {
                    _ = new LoggerLibrary("PddUnion", "PrecheckGoodsIdAsync").Info(urlWithQuery, body).SaveAsync();
                    var status = RegisterPrecheckException();
                    NotifyPrecheckException(goods_url, "RequestAsync", $"response.Successed=false\nbody:{body}", status.count, status.disabledNow);
                    return status.disabledNow ? RrecheckGoodsIdResult.Success : RrecheckGoodsIdResult.Exception;
                }

                var root = body.Convert2Object<GoodsSearchDTO>();
                if (root?.error_response != null)
                {
                    _ = new LoggerLibrary("PddUnion", "PrecheckGoodsIdAsync").Info(urlWithQuery, body).SaveAsync();
                    var status = RegisterPrecheckException();
                    var error = root.error_response;
                    NotifyPrecheckException(
                        goods_url,
                        "ErrorResponse",
                        $"error_code:{error.error_code}\nsub_code:{error.sub_code}\nerror_msg:{error.error_msg}\nsub_msg:{error.sub_msg}\nbody:{body}",
                        status.count,
                        status.disabledNow);
                    return status.disabledNow ? RrecheckGoodsIdResult.Success : RrecheckGoodsIdResult.Exception;
                }

                var goodsList = root?.goods_search_response?.goods_list;
                if (goodsList == null)
                {
                    _ = new LoggerLibrary("PddUnion", "PrecheckGoodsIdAsync").Info(urlWithQuery, body).SaveAsync();
                    var status = RegisterPrecheckException();
                    NotifyPrecheckException(goods_url, "GoodsSearchResponse", $"goods_list is null\nbody:{body}", status.count, status.disabledNow);
                    return status.disabledNow ? RrecheckGoodsIdResult.Success : RrecheckGoodsIdResult.Exception;
                }

                bool isValidGoods = goodsList.Any(item => item.goods_id > 0 && !string.IsNullOrWhiteSpace(item.goods_name));
                if (!isValidGoods && goodsList.Count > 0)
                {
                    _ = new LoggerLibrary("PddUnion", "PrecheckGoodsIdAsync.Empty").Info(urlWithQuery, body).SaveAsync();
                }

                ResetPrecheckExceptionState();
                return isValidGoods ? RrecheckGoodsIdResult.Success : RrecheckGoodsIdResult.Empty;
            }
            catch (Exception ex)
            {
                _ = new LoggerLibrary("PddUnion", "PrecheckGoodsIdAsync").Info(goods_url, ex.ToString()).SaveAsync();
                var status = RegisterPrecheckException();
                NotifyPrecheckException(goods_url, "Exception", ex.ToString(), status.count, status.disabledNow);
                return status.disabledNow ? RrecheckGoodsIdResult.Success : RrecheckGoodsIdResult.Exception;
            }


            //            client_id：c8823690b47842649e4fee054317e0c1
            //client_secret：0b5eeab761a6b61df59f11296387b95523a26b09


            //https://gw-api.pinduoduo.com/api/router

            //{
            //                "type": "pdd.ddk.goods.search",
            //    "data_type": "JSON",
            //    "client_id": "c8823690b47842649e4fee054317e0c1",
            //    "keyword": "https://mobile.yangkeduo.com/goods.html?ps=ROyjHRQJ7d",
            //    "pid": "13585632_187155840",
            //    "timestamp": 1779396871,
            //    "sign": "3DE407843BECA8BA480E8BA4C51E6049"
            //}

            //            这样可以用字符串链接去查询是否多多商品。返回goods_list里面有内容就是可以去转链的。

            //下面这个就是不能转链的
            //{
            //                "goods_search_response": {
            //                    "goods_list": [{
            //                        "subsidy_goods_type": 0,
            //            "subsidy_list": [],
            //            "platform_discount_list": [],
            //            "goods_id": 922492775451,
            //            "goods_sign": "E9L2dKKUUo9LeKDhwePAPXLcFjD6hB3MKw_JGaDyX4DX"
            //                    }],
            //        "total_count": 1,
            //        "request_id": "17793969978830062"
            //                }
            //            }
        }

        public async Task<PddDataDTO> PddParseAsync(string content, int commerceType, PddDataDTO result, CancellationToken cancellationToken = default)
        {
            string message = "OK";
            string url = GetLink(content);
            if (string.IsNullOrEmpty(url))
            {
                result.success = false;
                result.link_type = LinkTypeEnum.unknown;
                result.channel_type = ChannelTypeEnum.pdd;
                result.message = "放弃转链";
                result.reason = "无效链接";
                result.accountId = 0;
                result.accountName = string.Empty;
                result.content = content;
                return result;
            }
            string shortLinkurl = url;

            if (result.link_type == LinkTypeEnum.other_aff)
            {
                result.success = false;
                result.link_type = LinkTypeEnum.unknown;
                result.channel_type = ChannelTypeEnum.pdd;
                result.deeplink_url = GetDeeplink(url);
                result.message = "放弃转链";
                result.reason = "其他推广链接";
                result.accountId = 0;
                result.accountName = string.Empty;
                result.content = content;
                return result;
            }

            // 移到外围了
            //if (!TestParseCore.InWhitelist(result.ip, result.oaid) && FlowControlIgnoreRequest(_config, out string reason))
            //{
            //    result.success = false;
            //    result.link_type = LinkTypeEnum.unknown;
            //    result.channel_type = ChannelTypeEnum.pdd;
            //    result.message = "放弃转链";
            //    result.reason = reason;
            //    result.accountId = 0;
            //    result.accountName = string.Empty;
            //    result.content = content;
            //    result.deeplink_url = GetDeeplink(result.shortLinkurl);
            //    return result;
            //}


            var isTrackUrl = IsTrackUrl(url);
            //不是跟踪链接 ps=*** 就返回
            //2024-09-26 放开数字id转链
            //if (!isTrackUrl)
            //{
            //    result.success = false;
            //    result.link_type = LinkTypeEnum.unknown;
            //    result.channel_type = ChannelTypeEnum.pdd;
            //    result.message = "放弃转链";
            //    result.reason = "数字id链接";
            //    result.accountId = 0;
            //    result.accountName = string.Empty;
            //    result.content = content;
            //    return result;
            //}

            //去追踪
            Stopwatch stopwatch = Stopwatch.StartNew();
            stopwatch.Start();
            var redirectedUrl = await GetRedirectedUrlAsync(url, cancellationToken);
            stopwatch.Stop();
            bool redirected = !string.IsNullOrWhiteSpace(redirectedUrl) &&
                !string.Equals(redirectedUrl, url, StringComparison.OrdinalIgnoreCase);


            if (redirected)
            {
                // 字符串ID转数字ID
                result.rawContent2 = redirectedUrl;
                url = redirectedUrl;
                result.elapsedTime2 = (int)stopwatch.ElapsedMilliseconds;
            }

            switch (commerceType)
            {
                case 1:
                case 2:
                    result.success = false;
                    result.message = "放弃转链";
                    result.reason = $"厂商放弃{commerceType}";
                    return result;
            }

            Stopwatch stopwatch2 = Stopwatch.StartNew();
            stopwatch2.Start();

            result = _account.work_mode switch
            {
                PddUnionWorkMode.SiteApi => await UnionGeneratelink(result, url, cancellationToken),
                //case PddUnionWorkMode.AffApi:
                //    result = await GetPromotionByAffAsync(result, url, cancellationToken);
                //    break;
                _ => await transferUrl(result, url, cancellationToken),
            };


            if (!result.success)
            {
                result.shortLinkurl = shortLinkurl;
                result.deeplink_url = GetDeeplink(shortLinkurl);
            }



            stopwatch2.Stop();
            result.elapsedTime3 = (int)stopwatch2.ElapsedMilliseconds;
            return result;
        }
    }
}
