using System.Globalization;
using System.Net;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Xml.Linq;
using YMhut.Box.Core.Api;

namespace YMhut.Box.Core.Tools;

internal static class RemoteToolFormatter
{
    private static bool English(string? language) => string.Equals(language, "en-US", StringComparison.OrdinalIgnoreCase);

    private static string T(string? language, string zh, string en) => English(language) ? en : zh;

    public static ToolExecutionResult Format(ApiEndpoint endpoint, ApiResponse response, string input, string language = "zh-CN")
    {
        var header = Header(endpoint, response, language);
        var body = endpoint.Id switch
        {
            "baidu_hot" or "hotboard" or "bili_hot" or "zhihu_hot" => FormatDailyHot(response.Content, endpoint.Id),
            "tech_news" => FormatRss(response.Content),
            "earthquake_info" => FormatEarthquakes(response.Content),
            "dns_query" => FormatDns(response.Content),
            "ip_info" or "ip_lookup" or "rdap_ip_lookup" => FormatRdap(response.Content),
            "rdap_domain_lookup" or "domain_price" => FormatRdap(response.Content, endpoint.Id == "domain_price"),
            "history_today" => FormatPearHistoryToday(response.Content),
            "gold_price" => FormatLbmaGold(response.Content),
            "train_query" => FormatTrainStations(response.Content, input),
            "ai_latest_news" => FormatAiLatestNews(response.Content, language),
            "city_route_query" => FormatCityRoute(response.Content, language),
            "movie_box_office" => FormatMaoyanBoxOffice(response.Content, language),
            "football_news" or "cctv_news" or "oil_price" or "wx_domain_check" or "http_diagnostic" => FormatHtmlSummary(response.Content, endpoint),
            "qq_avatar" => response.Uri.ToString(),
            _ => Trim(response.Content)
        };
        body = LocalizeCommonBody(body, language);

        var output = $"{header}{Environment.NewLine}{Environment.NewLine}{body}".Trim();
        return ToolExecutionResult.Success(output, ToolResultBuilder.FromRemote(endpoint, response, output, language));
    }

    public static ToolExecutionResult FormatFailure(ApiEndpoint endpoint, ApiResponse response, string input, string language = "zh-CN")
    {
        var statusCode = response.StatusCode > 0 ? response.StatusCode.ToString(CultureInfo.InvariantCulture) : T(language, "未知", "unknown");
        var reason = string.IsNullOrWhiteSpace(response.Error)
            ? T(language, "上游接口没有返回成功状态。", "The upstream source did not return a success status.")
            : response.Error;
        var isForbidden = response.StatusCode is 401 or 403;
        var body = string.Join(Environment.NewLine, new[]
        {
            isForbidden
                ? T(language, "源站拒绝了自动请求。", "The source rejected the automated request.")
                : T(language, "远程数据暂时不可用。", "Remote data is temporarily unavailable."),
            T(language, $"状态码：{statusCode}", $"Status code: {statusCode}"),
            T(language, $"原因：{reason}", $"Reason: {reason}"),
            T(language, "建议：可以稍后重试，或打开公开来源页面查看。", "Suggestion: try again later, or open the public source page."),
            T(language, $"来源：{endpoint.SourceName}", $"Source: {endpoint.SourceName}")
        });
        var output = $"{Header(endpoint, response, language)}{Environment.NewLine}{Environment.NewLine}{body}".Trim();
        return ToolExecutionResult.Success(output, ToolResultBuilder.FromRemote(endpoint, response, output, language));
    }

    public static string Header(ApiEndpoint endpoint, ApiResponse response, string language = "zh-CN")
    {
        var official = endpoint.IsOfficial ? T(language, "官方/权威源", "official / authoritative source") : T(language, "公开可信源", "public trusted source");
        return string.Join(Environment.NewLine, new[]
        {
            T(language, $"数据源：{endpoint.SourceName}（{official}）", $"Data source: {endpoint.SourceName} ({official})"),
            T(language, "来源说明：已隐藏远程地址，仅展示脱敏来源名称。", "Source note: remote address is hidden; only sanitized source name is shown."),
            T(language, $"获取时间：{response.FetchedAt:yyyy-MM-dd HH:mm:ss zzz}", $"Fetched at: {response.FetchedAt:yyyy-MM-dd HH:mm:ss zzz}")
        });
    }

    public static string FormatWeather(ApiEndpoint endpoint, ApiResponse geocode, ApiResponse forecast, string language = "zh-CN")
    {
        var header = Header(endpoint, forecast, language);
        using var geocodeJson = JsonDocument.Parse(geocode.Content);
        var location = geocodeJson.RootElement.TryGetProperty("results", out var results) && results.ValueKind == JsonValueKind.Array && results.GetArrayLength() > 0
            ? results[0]
            : default;
        var locationName = location.ValueKind == JsonValueKind.Object
            ? $"{GetString(location, "name")} {GetString(location, "admin1")} {GetString(location, "country")}".Trim()
            : T(language, "未知位置", "Unknown location");

        using var forecastJson = JsonDocument.Parse(forecast.Content);
        var root = forecastJson.RootElement;
        var current = root.TryGetProperty("current", out var currentElement) ? currentElement : default;
        var daily = root.TryGetProperty("daily", out var dailyElement) ? dailyElement : default;

        var lines = new List<string>
        {
            T(language, $"位置：{locationName}", $"Location: {locationName}"),
            T(language, $"当前温度：{GetDouble(current, "temperature_2m"):0.#} °C", $"Current temperature: {GetDouble(current, "temperature_2m"):0.#} °C"),
            T(language, $"体感温度：{GetDouble(current, "apparent_temperature"):0.#} °C", $"Apparent temperature: {GetDouble(current, "apparent_temperature"):0.#} °C"),
            T(language, $"相对湿度：{GetDouble(current, "relative_humidity_2m"):0.#}%", $"Relative humidity: {GetDouble(current, "relative_humidity_2m"):0.#}%"),
            T(language, $"风速：{GetDouble(current, "wind_speed_10m"):0.#} km/h", $"Wind speed: {GetDouble(current, "wind_speed_10m"):0.#} km/h")
        };

        if (daily.ValueKind == JsonValueKind.Object &&
            daily.TryGetProperty("time", out var dates) &&
            daily.TryGetProperty("temperature_2m_max", out var max) &&
            daily.TryGetProperty("temperature_2m_min", out var min))
        {
            lines.Add(string.Empty);
            lines.Add(T(language, "未来三天：", "Next three days:"));
            var count = Math.Min(3, dates.GetArrayLength());
            for (var index = 0; index < count; index++)
            {
                lines.Add($"{dates[index].GetString()}: {min[index].GetDouble():0.#} - {max[index].GetDouble():0.#} °C");
            }
        }

        return $"{header}{Environment.NewLine}{Environment.NewLine}{string.Join(Environment.NewLine, lines)}";
    }

    public static string FormatTrainLeftTickets(ApiEndpoint endpoint, ApiResponse stationNames, ApiResponse leftTickets, string from, string to, string date)
    {
        var header = Header(endpoint, leftTickets);
        if (!TryJson(leftTickets.Content, out var document))
        {
            return $"{header}{Environment.NewLine}{Environment.NewLine}12306 返回了非 JSON 响应。已确认车站数据来自 12306，余票查询请稍后重试或检查日期是否在预售期内。";
        }

        using (document)
        {
            if (!document.RootElement.TryGetProperty("data", out var data) ||
                !data.TryGetProperty("result", out var result) ||
                result.ValueKind != JsonValueKind.Array)
            {
                return $"{header}{Environment.NewLine}{Environment.NewLine}未查询到 {date} {from} -> {to} 的车次。";
            }

            var lines = new List<string>
            {
                $"查询：{date} {from} -> {to}"
            };

            foreach (var row in result.EnumerateArray().Take(20))
            {
                var text = row.GetString() ?? string.Empty;
                var fields = text.Split('|');
                if (fields.Length < 33)
                {
                    continue;
                }

                lines.Add($"{fields[3]}  出发 {fields[8]}  到达 {fields[9]}  历时 {fields[10]}  二等座 {Blank(fields[30])}  一等座 {Blank(fields[31])}  商务座 {Blank(fields[32])}");
            }

            return $"{header}{Environment.NewLine}{Environment.NewLine}{string.Join(Environment.NewLine, lines)}";
        }
    }

    private static string LocalizeCommonBody(string body, string language)
    {
        if (!English(language))
        {
            return body;
        }

        var replacements = new Dictionary<string, string>
        {
            ["热度："] = "Heat: ",
            ["播放 "] = "Views ",
            ["发布时间："] = "Published: ",
            ["标题："] = "Title: ",
            ["摘要："] = "Summary: ",
            ["位置："] = "Location: ",
            ["震级："] = "Magnitude: ",
            ["深度："] = "Depth: ",
            ["时间："] = "Time: ",
            ["查询："] = "Query: ",
            ["出发 "] = "Depart ",
            ["到达 "] = "Arrive ",
            ["历时 "] = "Duration ",
            ["二等座 "] = "Second class ",
            ["一等座 "] = "First class ",
            ["商务座 "] = "Business class ",
            ["未查询到"] = "No result found for",
            ["返回了非 JSON 响应"] = "returned a non-JSON response",
            ["请稍后重试"] = "try again later"
        };

        foreach (var replacement in replacements)
        {
            body = body.Replace(replacement.Key, replacement.Value, StringComparison.Ordinal);
        }

        return body;
    }

    private static string FormatBaiduHot(string content)
    {
        var lines = new List<string>();
        if (TryJson(content, out var document))
        {
            using (document)
            {
                if (document.RootElement.TryGetProperty("data", out var data) &&
                    data.TryGetProperty("cards", out var cards))
                {
                    foreach (var card in cards.EnumerateArray())
                    {
                        if (!card.TryGetProperty("content", out var contentArray))
                        {
                            continue;
                        }

                        foreach (var item in contentArray.EnumerateArray().Take(20))
                        {
                            var title = GetString(item, "word");
                            if (string.IsNullOrWhiteSpace(title))
                            {
                                title = GetString(item, "title");
                            }
                            if (string.IsNullOrWhiteSpace(title))
                            {
                                continue;
                            }

                            var index = lines.Count + 1;
                            var desc = GetString(item, "desc");
                            var hotScore = FirstNonEmpty(GetString(item, "hotScore"), GetString(item, "score"), GetString(item, "heat"));
                            lines.Add(string.IsNullOrWhiteSpace(hotScore)
                                ? $"{index}. {title}"
                                : $"{index}. {title}  热度：{hotScore}");
                            if (!string.IsNullOrWhiteSpace(desc))
                            {
                                lines.Add($"   {desc}");
                            }
                        }
                    }
                }

                if (lines.Count == 0)
                {
                    lines.AddRange(CollectRankedJsonLines(document.RootElement, "热度"));
                }
            }
        }

        if (lines.Count == 0)
        {
            lines.AddRange(ExtractEmbeddedRankedLines(content));
        }

        return lines.Count == 0 ? Trim(content) : string.Join(Environment.NewLine, lines);
    }

    private static string FormatBiliHot(string content)
    {
        var lines = new List<string>();
        if (TryJson(content, out var document))
        {
            using (document)
            {
                if (document.RootElement.TryGetProperty("data", out var data) &&
                    data.TryGetProperty("list", out var list) &&
                    list.ValueKind == JsonValueKind.Array)
                {
                    foreach (var item in list.EnumerateArray().Take(20))
                    {
                        var title = GetString(item, "title");
                        if (string.IsNullOrWhiteSpace(title))
                        {
                            continue;
                        }

                        var owner = item.TryGetProperty("owner", out var ownerElement) ? GetString(ownerElement, "name") : string.Empty;
                        var views = item.TryGetProperty("stat", out var stat) ? GetInt64(stat, "view") : 0;
                        var meta = new List<string>();
                        if (!string.IsNullOrWhiteSpace(owner))
                        {
                            meta.Add(owner);
                        }
                        if (views > 0)
                        {
                            meta.Add($"播放 {views:N0}");
                        }
                        lines.Add(meta.Count == 0
                            ? $"{lines.Count + 1}. {title}"
                            : $"{lines.Count + 1}. {title} / {string.Join(" / ", meta)}");
                    }
                }

                if (lines.Count == 0)
                {
                    lines.AddRange(CollectRankedJsonLines(document.RootElement, "播放"));
                }
            }
        }

        if (lines.Count == 0)
        {
            lines.AddRange(ExtractEmbeddedRankedLines(content));
        }

        return lines.Count == 0 ? Trim(content) : string.Join(Environment.NewLine, lines);
    }

    private static string FormatZhihuHot(string content)
    {
        if (!TryJson(content, out var document))
        {
            var extracted = ExtractEmbeddedRankedLines(content);
            return extracted.Count == 0 ? FormatHtmlAnchors(content) : string.Join(Environment.NewLine, extracted);
        }

        using (document)
        {
            if (!document.RootElement.TryGetProperty("data", out var data))
            {
                var fallback = CollectRankedJsonLines(document.RootElement, "热度");
                return fallback.Count == 0 ? Trim(content) : string.Join(Environment.NewLine, fallback);
            }

            var lines = new List<string>();
            foreach (var item in data.EnumerateArray().Take(20))
            {
                var target = item.TryGetProperty("target", out var targetElement) ? targetElement : item;
                var title = GetString(target, "title");
                if (string.IsNullOrWhiteSpace(title))
                {
                    continue;
                }

                var metric = FirstNonEmpty(GetString(item, "detail_text"), GetString(item, "metrics"), GetString(target, "excerpt"));
                lines.Add(string.IsNullOrWhiteSpace(metric)
                    ? $"{lines.Count + 1}. {title}"
                    : $"{lines.Count + 1}. {title} / {metric}");
            }

            if (lines.Count == 0)
            {
                lines.AddRange(CollectRankedJsonLines(document.RootElement, "热度"));
            }

            return lines.Count == 0 ? Trim(content) : string.Join(Environment.NewLine, lines);
        }
    }

    private static string FormatDailyHot(string content, string endpointId)
    {
        if (!TryJson(content, out var document))
        {
            var extracted = ExtractEmbeddedRankedLines(content);
            return extracted.Count == 0 ? Trim(content) : string.Join(Environment.NewLine, extracted);
        }

        using (document)
        {
            var root = document.RootElement;
            var lines = new List<string>();

            if (TryEnumerateDailyHotPlatforms(root, out var platforms))
            {
                lines.Add("平台列表");
                foreach (var (platform, index) in platforms.Take(40).Select((item, index) => (item, index)))
                {
                    var name = FirstNonEmpty(GetString(platform, "title"), GetString(platform, "name"), GetString(platform, "type"));
                    if (string.IsNullOrWhiteSpace(name))
                    {
                        continue;
                    }

                    var summary = FirstNonEmpty(GetString(platform, "description"), GetString(platform, "desc"), GetString(platform, "updateTime"));
                    var link = FirstNonEmpty(GetString(platform, "link"), GetString(platform, "url"), GetString(platform, "mobileUrl"));
                    var line = $"{index + 1}. {name}";
                    if (!string.IsNullOrWhiteSpace(summary))
                    {
                        line += $" / {summary}";
                    }
                    if (!string.IsNullOrWhiteSpace(link))
                    {
                        line += $" / {link}";
                    }
                    lines.Add(line);
                }

                if (lines.Count > 1)
                {
                    return string.Join(Environment.NewLine, lines);
                }
            }

            var items = TryEnumerateDailyHotItems(root, endpointId);
            foreach (var (item, index) in items.Take(40).Select((value, itemIndex) => (value, itemIndex)))
            {
                var rank = FirstNonEmpty(GetString(item, "id"), GetString(item, "top"), GetString(item, "rank"));
                var title = FirstNonEmpty(GetString(item, "title"), GetString(item, "name"), GetString(item, "word"));
                if (string.IsNullOrWhiteSpace(title))
                {
                    continue;
                }

                var meta = new List<string>();
                var ownerName = item.TryGetProperty("owner", out var owner) && owner.ValueKind == JsonValueKind.Object
                    ? GetString(owner, "name")
                    : string.Empty;
                if (!string.IsNullOrWhiteSpace(ownerName))
                {
                    meta.Add(ownerName);
                }
                if (item.TryGetProperty("stat", out var stat) && stat.ValueKind == JsonValueKind.Object)
                {
                    var views = GetInt64(stat, "view");
                    if (views > 0)
                    {
                        meta.Add($"播放 {views:N0}");
                    }
                }

                var summary = FirstNonEmpty(GetString(item, "desc"), GetString(item, "summary"), GetString(item, "hot"), GetString(item, "timestamp"));
                if (!string.IsNullOrWhiteSpace(summary))
                {
                    meta.Add(summary);
                }
                var link = FirstNonEmpty(GetString(item, "url"), GetString(item, "mobileUrl"), GetString(item, "link"));
                var line = string.IsNullOrWhiteSpace(rank) ? $"{index + 1}. {title}" : $"{rank}. {title}";
                if (meta.Count > 0)
                {
                    line += $" / {string.Join(" / ", meta)}";
                }
                if (!string.IsNullOrWhiteSpace(link))
                {
                    line += $" / {link}";
                }
                lines.Add(line);
            }

            if (lines.Count == 0)
            {
                lines.AddRange(CollectRankedJsonLines(root, "热度"));
            }

            return lines.Count == 0 ? Trim(content) : string.Join(Environment.NewLine, lines);
        }
    }

    private static bool TryEnumerateDailyHotPlatforms(JsonElement root, out IEnumerable<JsonElement> platforms)
    {
        platforms = [];
        if (root.ValueKind == JsonValueKind.Object)
        {
            if (root.TryGetProperty("data", out var data) && data.ValueKind == JsonValueKind.Array)
            {
                platforms = data.EnumerateArray();
                return true;
            }

            if (root.TryGetProperty("formCache", out var formCache) && formCache.ValueKind == JsonValueKind.Array)
            {
                platforms = formCache.EnumerateArray();
                return true;
            }

            if (root.TryGetProperty("data", out data) && data.ValueKind == JsonValueKind.Object && data.TryGetProperty("data", out var nested) && nested.ValueKind == JsonValueKind.Array)
            {
                platforms = nested.EnumerateArray();
                return true;
            }
        }

        return false;
    }

    private static IEnumerable<JsonElement> TryEnumerateDailyHotItems(JsonElement root, string endpointId)
    {
        if (root.ValueKind != JsonValueKind.Object)
        {
            return [];
        }

        if (root.TryGetProperty("data", out var data))
        {
            if (data.ValueKind == JsonValueKind.Array)
            {
                return data.EnumerateArray();
            }

            if (data.ValueKind == JsonValueKind.Object)
            {
                foreach (var candidateName in new[] { "list", "cards", "items", "data", "result" })
                {
                    if (data.TryGetProperty(candidateName, out var nested) && nested.ValueKind == JsonValueKind.Array)
                    {
                        return nested.EnumerateArray();
                    }
                }
            }
        }

        if (root.TryGetProperty("cards", out var cards) && cards.ValueKind == JsonValueKind.Array)
        {
            return cards.EnumerateArray();
        }

        if (endpointId.Equals("hotboard", StringComparison.OrdinalIgnoreCase) && root.TryGetProperty("formCache", out var formCache) && formCache.ValueKind == JsonValueKind.Array)
        {
            return formCache.EnumerateArray();
        }

        return [];
    }

    private static string FormatPearHistoryToday(string content)
    {
        if (TryJson(content, out var document))
        {
            using (document)
            {
                var root = document.RootElement;
                if (root.TryGetProperty("data", out var data) && data.ValueKind == JsonValueKind.String)
                {
                    content = data.GetString() ?? content;
                }
                else if (root.TryGetProperty("data", out data) && data.ValueKind == JsonValueKind.Object)
                {
                    content = JsonSerializer.Serialize(data);
                }
                else if (root.TryGetProperty("data", out data) && data.ValueKind == JsonValueKind.Array)
                {
                    content = JsonSerializer.Serialize(data);
                }
            }
        }

        if (TryJson(content, out var historyDocument))
        {
            using (historyDocument)
            {
                var root = historyDocument.RootElement;
                var lines = new List<string>();
                foreach (var section in new[] { "events", "births", "deaths", "holidays" })
                {
                    if (!root.TryGetProperty(section, out var items) || items.ValueKind != JsonValueKind.Array)
                    {
                        continue;
                    }

                    lines.Add(section.ToUpperInvariant());
                    foreach (var item in items.EnumerateArray().Take(12))
                    {
                        var year = FirstNonEmpty(GetString(item, "year"), GetString(item, "date"));
                        var text = StripHtml(FirstNonEmpty(GetString(item, "text"), GetString(item, "title"), GetString(item, "summary")));
                        if (!string.IsNullOrWhiteSpace(text))
                        {
                            lines.Add(string.IsNullOrWhiteSpace(year) ? $"- {text}" : $"- {year}: {text}");
                        }
                    }

                    lines.Add(string.Empty);
                }

                return lines.Count == 0 ? Trim(content) : string.Join(Environment.NewLine, lines).Trim();
            }
        }

        return Trim(content);
    }

    private static string FormatAiLatestNews(string content, string language)
    {
        if (!TryJson(content, out var document))
        {
            return Trim(content);
        }

        using (document)
        {
            var root = document.RootElement;
            var lines = new List<string>();
            var categories = new[]
            {
                "models_and_releases",
                "tools_and_frameworks",
                "research_and_papers",
                "industry_and_business",
                "applications_and_use_cases",
                "technical_discussions",
                "ethics_and_safety"
            };

            foreach (var category in categories)
            {
                if (!root.TryGetProperty("data", out var data) || data.ValueKind != JsonValueKind.Object || !data.TryGetProperty(category, out var items) || items.ValueKind != JsonValueKind.Array)
                {
                    continue;
                }

                var label = category.Replace('_', ' ');
                lines.Add(label);
                foreach (var item in items.EnumerateArray().Take(8))
                {
                    var created = FirstNonEmpty(GetString(item, "created_at"), GetString(item, "published_at"), GetString(item, "time"));
                    var title = FirstNonEmpty(GetString(item, "title"), GetString(item, "name"));
                    var summary = FirstNonEmpty(GetString(item, "summary"), GetString(item, "description"));
                    var source = FirstNonEmpty(GetString(item, "source"), GetString(item, "site"));
                    var url = FirstNonEmpty(GetString(item, "url"), GetString(item, "link"));
                    if (string.IsNullOrWhiteSpace(title))
                    {
                        continue;
                    }

                    var line = string.IsNullOrWhiteSpace(created) ? $"{lines.Count + 1}. {title}" : $"{lines.Count + 1}. {title} / {created}";
                    if (!string.IsNullOrWhiteSpace(source))
                    {
                        line += $" / {source}";
                    }
                    if (!string.IsNullOrWhiteSpace(summary))
                    {
                        line += $" / {summary}";
                    }
                    if (!string.IsNullOrWhiteSpace(url))
                    {
                        line += $" / {url}";
                    }
                    lines.Add(line);
                }
                lines.Add(string.Empty);
            }

            return lines.Count == 0 ? Trim(content) : string.Join(Environment.NewLine, lines).Trim();
        }
    }

    private static string FormatCityRoute(string content, string language)
    {
        if (!TryJson(content, out var document))
        {
            return Trim(content);
        }

        using (document)
        {
            var root = document.RootElement;
            var data = root.TryGetProperty("data", out var dataElement) ? dataElement : root;
            var lines = new List<string>();
            foreach (var pair in new[] {
                ("from", "出发"),
                ("to", "到达"),
                ("distance", "距离"),
                ("time", "耗时"),
                ("fuelcosts", "油费"),
                ("bridgetoll", "过路费"),
                ("totalcost", "总成本"),
                ("roadconditions", "路况")
            })
            {
                var value = GetString(data, pair.Item1);
                if (!string.IsNullOrWhiteSpace(value))
                {
                    lines.Add($"{pair.Item2}: {value}");
                }
            }

            if (lines.Count == 0)
            {
                foreach (var property in data.EnumerateObject())
                {
                    if (property.Value.ValueKind is JsonValueKind.String or JsonValueKind.Number)
                    {
                        lines.Add($"{property.Name}: {property.Value.GetRawText().Trim('"')}");
                    }
                }
            }

            return lines.Count == 0 ? Trim(content) : string.Join(Environment.NewLine, lines);
        }
    }

    private static string FormatMaoyanBoxOffice(string content, string language)
    {
        if (!TryJson(content, out var document))
        {
            return Trim(content);
        }

        using (document)
        {
            var root = document.RootElement;
            var items = root.ValueKind == JsonValueKind.Array ? root.EnumerateArray() :
                root.TryGetProperty("data", out var data) && data.ValueKind == JsonValueKind.Array ? data.EnumerateArray() :
                root.TryGetProperty("data", out data) && data.ValueKind == JsonValueKind.Object && data.TryGetProperty("data", out var nested) && nested.ValueKind == JsonValueKind.Array ? nested.EnumerateArray() :
                root.TryGetProperty("data", out data) && data.ValueKind == JsonValueKind.Object && data.TryGetProperty("list", out nested) && nested.ValueKind == JsonValueKind.Array ? nested.EnumerateArray() :
                [];

            var lines = new List<string>();
            foreach (var item in items.Take(20))
            {
                var rank = FirstNonEmpty(GetString(item, "top"), GetString(item, "rank"));
                var title = FirstNonEmpty(GetString(item, "movieName"), GetString(item, "title"), GetString(item, "name"));
                if (string.IsNullOrWhiteSpace(title))
                {
                    continue;
                }

                var summary = FirstNonEmpty(GetString(item, "releaseInfo"), GetString(item, "sumBoxDesc"), GetString(item, "boxRate"), GetString(item, "showCount"), GetString(item, "showCountRate"), GetString(item, "avgShowView"), GetString(item, "avgSeatView"));
                var line = string.IsNullOrWhiteSpace(rank) ? title : $"{rank}. {title}";
                if (!string.IsNullOrWhiteSpace(summary))
                {
                    line += $" / {summary}";
                }
                lines.Add(line);
            }

            return lines.Count == 0 ? Trim(content) : string.Join(Environment.NewLine, lines);
        }
    }

    private static IReadOnlyList<string> CollectRankedJsonLines(JsonElement root, string metricLabel)
    {
        var lines = new List<string>();
        var seen = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

        void Visit(JsonElement element, int depth)
        {
            if (lines.Count >= 40 || depth > 10)
            {
                return;
            }

            if (element.ValueKind == JsonValueKind.Object)
            {
                var title = FirstNonEmpty(
                    GetString(element, "title"),
                    GetString(element, "word"),
                    GetString(element, "name_text"),
                    GetString(element, "display_title"));
                if (IsUsefulRankTitle(title) && seen.Add(title))
                {
                    var meta = new List<string>();
                    if (element.TryGetProperty("owner", out var owner) && owner.ValueKind == JsonValueKind.Object)
                    {
                        var ownerName = GetString(owner, "name");
                        if (!string.IsNullOrWhiteSpace(ownerName))
                        {
                            meta.Add(ownerName);
                        }
                    }

                    if (element.TryGetProperty("stat", out var stat) && stat.ValueKind == JsonValueKind.Object)
                    {
                        var views = GetInt64(stat, "view");
                        if (views > 0)
                        {
                            meta.Add($"播放 {views:N0}");
                        }
                    }

                    var heat = FirstNonEmpty(
                        GetString(element, "hotScore"),
                        GetString(element, "hot_score"),
                        GetString(element, "heat"),
                        GetString(element, "score"),
                        GetString(element, "detail_text"),
                        GetString(element, "metrics"));
                    if (!string.IsNullOrWhiteSpace(heat))
                    {
                        meta.Add($"{metricLabel}：{heat}");
                    }

                    var desc = FirstNonEmpty(GetString(element, "desc"), GetString(element, "excerpt"), GetString(element, "summary"));
                    lines.Add(meta.Count == 0
                        ? $"{lines.Count + 1}. {title}"
                        : $"{lines.Count + 1}. {title} / {string.Join(" / ", meta)}");
                    if (!string.IsNullOrWhiteSpace(desc) &&
                        !desc.Equals(title, StringComparison.OrdinalIgnoreCase) &&
                        desc.Length <= 180)
                    {
                        lines.Add($"   {desc}");
                    }
                }

                foreach (var property in element.EnumerateObject())
                {
                    Visit(property.Value, depth + 1);
                }
                return;
            }

            if (element.ValueKind == JsonValueKind.Array)
            {
                foreach (var item in element.EnumerateArray())
                {
                    Visit(item, depth + 1);
                }
            }
        }

        Visit(root, 0);
        return lines;
    }

    private static IReadOnlyList<string> ExtractEmbeddedRankedLines(string content)
    {
        var titles = new List<string>();
        var seen = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

        foreach (Match match in Regex.Matches(content, @"""(?:title|word)""\s*:\s*""(?<value>(?:\\.|[^""\\])+)""", RegexOptions.IgnoreCase))
        {
            var value = DecodeJsonString(match.Groups["value"].Value);
            if (IsUsefulRankTitle(value) && seen.Add(value))
            {
                titles.Add(value);
                if (titles.Count >= 30)
                {
                    break;
                }
            }
        }

        if (titles.Count == 0)
        {
            foreach (var anchor in HtmlAnchorTexts(content))
            {
                if (IsUsefulRankTitle(anchor) && seen.Add(anchor))
                {
                    titles.Add(anchor);
                    if (titles.Count >= 30)
                    {
                        break;
                    }
                }
            }
        }

        return titles
            .Take(20)
            .Select((title, index) => $"{index + 1}. {title}")
            .ToArray();
    }

    private static IEnumerable<string> HtmlAnchorTexts(string content)
    {
        foreach (Match match in Regex.Matches(content, @"<a[^>]*>(.*?)</a>", RegexOptions.IgnoreCase | RegexOptions.Singleline))
        {
            var text = StripHtml(match.Groups[1].Value);
            if (!string.IsNullOrWhiteSpace(text))
            {
                yield return text;
            }
        }
    }

    private static string DecodeJsonString(string value)
    {
        try
        {
            return JsonSerializer.Deserialize<string>($"\"{value}\"") ?? string.Empty;
        }
        catch
        {
            return WebUtility.HtmlDecode(value.Replace("\\/", "/", StringComparison.Ordinal)).Trim();
        }
    }

    private static bool IsUsefulRankTitle(string? value)
    {
        if (string.IsNullOrWhiteSpace(value))
        {
            return false;
        }

        var text = value.Trim();
        if (text.Length < 2 || text.Length > 160)
        {
            return false;
        }

        return !text.StartsWith("http://", StringComparison.OrdinalIgnoreCase) &&
            !text.StartsWith("https://", StringComparison.OrdinalIgnoreCase) &&
            !text.Contains("<", StringComparison.Ordinal) &&
            !text.Contains(">", StringComparison.Ordinal) &&
            !text.Equals("更多", StringComparison.OrdinalIgnoreCase) &&
            !text.Equals("首页", StringComparison.OrdinalIgnoreCase);
    }

    private static string FirstNonEmpty(params string[] values)
        => values.FirstOrDefault(value => !string.IsNullOrWhiteSpace(value)) ?? string.Empty;

    private static string FormatRss(string content)
    {
        var document = XDocument.Parse(content);
        var items = document.Descendants("item").Take(20);
        var lines = items
            .Select((item, index) => $"{index + 1}. {Value(item, "title")}{Environment.NewLine}   {Value(item, "link")}")
            .ToList();
        return lines.Count == 0 ? Trim(content) : string.Join(Environment.NewLine, lines);
    }

    private static string FormatEarthquakes(string content)
    {
        using var document = JsonDocument.Parse(content);
        var features = document.RootElement.GetProperty("features").EnumerateArray();
        var lines = new List<string>();
        foreach (var feature in features.Take(20))
        {
            var properties = feature.GetProperty("properties");
            var time = DateTimeOffset.FromUnixTimeMilliseconds(GetInt64(properties, "time")).ToLocalTime();
            lines.Add($"{lines.Count + 1}. M{GetDouble(properties, "mag"):0.#} {GetString(properties, "place")} / {time:yyyy-MM-dd HH:mm}");
        }

        return string.Join(Environment.NewLine, lines);
    }

    private static string FormatDns(string content)
    {
        using var document = JsonDocument.Parse(content);
        var root = document.RootElement;
        var lines = new List<string>
        {
            $"Status: {GetInt64(root, "Status")}",
            $"Question: {GetString(root.GetProperty("Question")[0], "name")}"
        };
        if (root.TryGetProperty("Answer", out var answers))
        {
            foreach (var answer in answers.EnumerateArray())
            {
                lines.Add($"{GetString(answer, "name")}  TYPE {GetInt64(answer, "type")}  TTL {GetInt64(answer, "TTL")}  {GetString(answer, "data")}");
            }
        }

        return string.Join(Environment.NewLine, lines);
    }

    private static string FormatRdap(string content, bool domainPriceMode = false)
    {
        using var document = JsonDocument.Parse(content);
        var root = document.RootElement;
        var lines = new List<string>();
        if (domainPriceMode)
        {
            lines.Add("说明：域名零售价格由各注册商制定，IANA/RDAP 不提供官方零售价；这里展示官方注册与 RDAP 信息。");
            lines.Add(string.Empty);
        }

        foreach (var key in new[] { "objectClassName", "handle", "ldhName", "name", "country", "startAddress", "endAddress" })
        {
            var value = GetString(root, key);
            if (!string.IsNullOrWhiteSpace(value))
            {
                lines.Add($"{key}: {value}");
            }
        }

        if (root.TryGetProperty("events", out var events))
        {
            foreach (var item in events.EnumerateArray().Take(8))
            {
                lines.Add($"{GetString(item, "eventAction")}: {GetString(item, "eventDate")}");
            }
        }

        if (root.TryGetProperty("notices", out var notices))
        {
            foreach (var notice in notices.EnumerateArray().Take(3))
            {
                lines.Add($"Notice: {GetString(notice, "title")}");
            }
        }

        return lines.Count == 0 ? Trim(content) : string.Join(Environment.NewLine, lines);
    }

    private static string FormatOnThisDay(string content)
    {
        using var document = JsonDocument.Parse(content);
        var lines = new List<string>();
        foreach (var section in new[] { "events", "births", "deaths", "holidays" })
        {
            if (!document.RootElement.TryGetProperty(section, out var items))
            {
                continue;
            }

            lines.Add(section.ToUpperInvariant());
            foreach (var item in items.EnumerateArray().Take(8))
            {
                var year = GetInt64(item, "year");
                var text = StripHtml(GetString(item, "text"));
                lines.Add($"- {year}: {text}");
            }
            lines.Add(string.Empty);
        }

        return lines.Count == 0 ? Trim(content) : string.Join(Environment.NewLine, lines).Trim();
    }

    private static string FormatLbmaGold(string content)
    {
        using var document = JsonDocument.Parse(content);
        var items = document.RootElement.EnumerateArray()
            .Where(item => item.TryGetProperty("v", out var values) && values.ValueKind == JsonValueKind.Array && values.GetArrayLength() >= 2 && values[0].ValueKind == JsonValueKind.Number)
            .ToArray();
        var latest = items.LastOrDefault();
        if (latest.ValueKind != JsonValueKind.Object)
        {
            return Trim(content);
        }

        var date = GetString(latest, "d");
        var v = latest.GetProperty("v");
        var builder = new StringBuilder()
            .AppendLine("LBMA Gold PM Fixing")
            .AppendLine($"日期：{date}")
            .AppendLine($"USD/oz：{v[0].GetDouble():0.##}")
            .AppendLine($"GBP/oz：{v[1].GetDouble():0.##}")
            .AppendLine()
            .AppendLine("Date | USD/oz | GBP/oz");

        foreach (var item in items.TakeLast(30))
        {
            var values = item.GetProperty("v");
            builder.AppendLine($"{GetString(item, "d")} | {values[0].GetDouble():0.##} | {values[1].GetDouble():0.##}");
        }

        return builder.ToString().Trim();
    }

    private static string FormatTrainStations(string content, string input)
    {
        var stations = ParseStations(content);
        if (string.IsNullOrWhiteSpace(input))
        {
            return string.Join(Environment.NewLine, stations.Take(20).Select(station => $"{station.Name} / {station.Code} / {station.Pinyin}"));
        }

        var matches = stations
            .Where(station => station.Name.Contains(input, StringComparison.OrdinalIgnoreCase) ||
                station.Code.Contains(input, StringComparison.OrdinalIgnoreCase) ||
                station.Pinyin.Contains(input, StringComparison.OrdinalIgnoreCase))
            .Take(30)
            .Select(station => $"{station.Name} / {station.Code} / {station.Pinyin}")
            .ToList();
        return matches.Count == 0 ? "未命中车站；可输入中文站名、拼音或 12306 车站代码。" : string.Join(Environment.NewLine, matches);
    }

    public static IReadOnlyList<TrainStation> ParseStations(string content)
    {
        var payload = content.Split('\'').Length >= 2 ? content.Split('\'')[1] : content;
        return payload.Split('@', StringSplitOptions.RemoveEmptyEntries)
            .Select(row => row.Split('|'))
            .Where(parts => parts.Length >= 5)
            .Select(parts => new TrainStation(parts[1], parts[2], parts[3]))
            .ToArray();
    }

    private static string FormatHtmlSummary(string content, ApiEndpoint endpoint)
    {
        var title = Regex.Match(content, @"<title[^>]*>(.*?)</title>", RegexOptions.IgnoreCase | RegexOptions.Singleline).Groups[1].Value;
        title = StripHtml(title);
        var anchors = Regex.Matches(content, @"<a[^>]*>(.*?)</a>", RegexOptions.IgnoreCase | RegexOptions.Singleline)
            .Select(match => StripHtml(match.Groups[1].Value))
            .Where(text => text.Length >= 6)
            .Distinct()
            .Take(10)
            .ToArray();

        var lines = new List<string>
        {
            string.IsNullOrWhiteSpace(title) ? endpoint.Name : title
        };
        lines.AddRange(anchors.Select((anchor, index) => $"{index + 1}. {anchor}"));

        if (endpoint.Id == "wx_domain_check")
        {
            lines.Add(string.Empty);
            lines.Add("说明：微信没有开放匿名域名状态查询官方接口；请在微信公众平台、安全中心或已授权开放平台能力中进行最终校验。");
        }

        return string.Join(Environment.NewLine, lines);
    }

    private static string FormatHtmlAnchors(string content)
    {
        var anchors = Regex.Matches(content, @"<a[^>]*>(.*?)</a>", RegexOptions.IgnoreCase | RegexOptions.Singleline)
            .Select(match => StripHtml(match.Groups[1].Value))
            .Where(text => text.Length >= 4 && text.Length <= 120)
            .Distinct()
            .Take(20)
            .Select((text, index) => $"{index + 1}. {text}")
            .ToArray();
        return anchors.Length == 0 ? Trim(content) : string.Join(Environment.NewLine, anchors);
    }

    private static bool TryJson(string content, out JsonDocument document)
    {
        try
        {
            document = JsonDocument.Parse(content);
            return true;
        }
        catch
        {
            document = default!;
            return false;
        }
    }

    private static string Trim(string content)
    {
        return content.Length > 6000 ? content[..6000] + Environment.NewLine + "...(truncated)" : content.Trim();
    }

    private static string GetString(JsonElement element, string name)
    {
        if (!element.TryGetProperty(name, out var value))
        {
            return string.Empty;
        }

        return value.ValueKind switch
        {
            JsonValueKind.String => value.GetString() ?? string.Empty,
            JsonValueKind.Number => value.GetRawText(),
            JsonValueKind.True => "true",
            JsonValueKind.False => "false",
            _ => string.Empty
        };
    }

    private static double GetDouble(JsonElement element, string name)
    {
        return element.ValueKind == JsonValueKind.Object &&
            element.TryGetProperty(name, out var value) &&
            value.ValueKind == JsonValueKind.Number
            ? value.GetDouble()
            : 0;
    }

    private static long GetInt64(JsonElement element, string name)
    {
        return element.ValueKind == JsonValueKind.Object &&
            element.TryGetProperty(name, out var value) &&
            value.ValueKind == JsonValueKind.Number
            ? value.GetInt64()
            : 0;
    }

    private static string Value(XElement item, string name)
    {
        return item.Elements().FirstOrDefault(element => element.Name.LocalName.Equals(name, StringComparison.OrdinalIgnoreCase))?.Value.Trim() ?? string.Empty;
    }

    private static string StripHtml(string value)
    {
        return WebUtility.HtmlDecode(Regex.Replace(value, "<.*?>", string.Empty, RegexOptions.Singleline)).Trim();
    }

    private static string Blank(string value)
    {
        return string.IsNullOrWhiteSpace(value) || value == "--" ? "无" : value;
    }
}

internal sealed record TrainStation(string Name, string Code, string Pinyin);
