namespace YMhut.Box.Core.Api;

public enum ApiSourceVisibility
{
    PublicOfficial,
    PublicTrusted,
    SensitivePrivate
}

public sealed record ApiEndpoint(
    string Id,
    string Name,
    string UriTemplate,
    string SourceName,
    string SourceUrl,
    bool IsOfficial = true,
    ApiSourceVisibility? VisibilityOverride = null)
{
    public ApiSourceVisibility SourceVisibility =>
        VisibilityOverride ?? (IsOfficial ? ApiSourceVisibility.PublicOfficial : ApiSourceVisibility.PublicTrusted);

    public bool ShouldHideEndpoint => SourceVisibility == ApiSourceVisibility.SensitivePrivate ||
        Id.Equals("http_diagnostic", StringComparison.OrdinalIgnoreCase) ||
        UriTemplate.Contains("update.ymhut.cn", StringComparison.OrdinalIgnoreCase) ||
        UriTemplate.Contains("api.pearapi.ai", StringComparison.OrdinalIgnoreCase);
}

public static class ApiEndpoints
{
    private const string PearApiBase = "https://api.pearapi.ai";
    private const string DailyHotBase = PearApiBase + "/api/dailyhot/";
    private const string AiLatestNewsBase = PearApiBase + "/api/latest_ai_consultative";
    private const string HistoryTodayBase = PearApiBase + "/api/lsjt/?type=json";
    private const string CityRouteBase = PearApiBase + "/api/citytravelroutes/";
    private const string MaoyanBase = PearApiBase + "/api/maoyan/";

    private static readonly IReadOnlyDictionary<string, string> DailyHotShortcuts = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
    {
        ["baidu_hot"] = "百度",
        ["bili_hot"] = "哔哩哔哩",
        ["zhihu_hot"] = "知乎"
    };

    private static readonly IReadOnlyDictionary<string, ApiEndpoint> Endpoints = new Dictionary<string, ApiEndpoint>(StringComparer.OrdinalIgnoreCase)
    {
        ["baidu_hot"] = new("baidu_hot", "百度热搜", DailyHotBase, "PearAPI DailyHot", PearApiBase, true, ApiSourceVisibility.SensitivePrivate),
        ["bili_hot"] = new("bili_hot", "B 站热榜", DailyHotBase, "PearAPI DailyHot", PearApiBase, true, ApiSourceVisibility.SensitivePrivate),
        ["zhihu_hot"] = new("zhihu_hot", "知乎热榜", DailyHotBase, "PearAPI DailyHot", PearApiBase, true, ApiSourceVisibility.SensitivePrivate),
        ["hotboard"] = new("hotboard", "今日热榜", DailyHotBase, "PearAPI DailyHot", PearApiBase, true, ApiSourceVisibility.SensitivePrivate),
        ["football_news"] = new("football_news", "体育新闻", "https://www.fifa.com/en", "FIFA", "https://www.fifa.com/en"),
        ["tech_news"] = new("tech_news", "科技新闻", "https://36kr.com/feed", "36Kr RSS", "https://36kr.com/feed"),
        ["cctv_news"] = new("cctv_news", "央视新闻", "https://news.cctv.com/", "CCTV News", "https://news.cctv.com/"),
        ["earthquake_info"] = new("earthquake_info", "地震信息", "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/2.5_day.geojson", "USGS Earthquake Hazards Program", "https://earthquake.usgs.gov/earthquakes/feed/v1.0/geojson.php"),
        ["ip_info"] = new("ip_info", "IP / 域名详情", "https://rdap.org/ip/{value}", "RDAP", "https://www.iana.org/rdap"),
        ["ip_lookup"] = new("ip_lookup", "IP RDAP 查询", "https://rdap.org/ip/{value}", "RDAP", "https://www.iana.org/rdap"),
        ["dns_query"] = new("dns_query", "DNS 解析", "https://dns.google/resolve?name={value}&type=A", "Google Public DNS", "https://developers.google.com/speed/public-dns/docs/doh/json"),
        ["weather"] = new("weather", "天气查询", "https://geocoding-api.open-meteo.com/v1/search?name={value}&count=1&language=zh&format=json", "Open-Meteo", "https://open-meteo.com/", false),
        ["history_today"] = new("history_today", "历史上的今天", HistoryTodayBase, "PearAPI History Today", PearApiBase, true, ApiSourceVisibility.SensitivePrivate),
        ["domain_price"] = new("domain_price", "域名官方信息", "https://rdap.org/domain/{value}", "RDAP", "https://www.iana.org/rdap"),
        ["wx_domain_check"] = new("wx_domain_check", "微信域名检查说明", "https://developers.weixin.qq.com/doc/", "微信公众平台文档", "https://developers.weixin.qq.com/doc/"),
        ["qq_avatar"] = new("qq_avatar", "QQ 信息", "https://uapis.cn/api/v1/social/qq/userinfo?qq={value}", "Uapis QQ User Info", "https://uapis.cn/docs/api-reference/get-social-qq-userinfo", false, ApiSourceVisibility.SensitivePrivate),
        ["qq_profile"] = new("qq_profile", "QQ 公开资料", "https://r.qzone.qq.com/fcg-bin/cgi_get_portrait.fcg?uins={value}", "QQ 公开资料源", "https://qzone.qq.com/", false),
        ["gold_price"] = new("gold_price", "黄金价格", "https://prices.lbma.org.uk/json/gold_pm.json", "LBMA Precious Metal Prices", "https://www.lbma.org.uk/prices-and-data/precious-metal-prices"),
        ["oil_price"] = new("oil_price", "成品油价格政策", "https://www.ndrc.gov.cn/", "国家发展改革委", "https://www.ndrc.gov.cn/", true),
        ["movie_box_office"] = new("movie_box_office", "电影票房", MaoyanBase, "PearAPI Maoyan", PearApiBase, true, ApiSourceVisibility.SensitivePrivate),
        ["media_types"] = new("media_types", "随机放映室远程配置", "https://update.ymhut.cn/media-types.json", "YMhut Remote Config", "https://update.ymhut.cn/media-types.json", false, ApiSourceVisibility.SensitivePrivate),
        ["train_query"] = new("train_query", "铁路车站数据", "https://kyfw.12306.cn/otn/resources/js/framework/station_name.js", "中国铁路 12306", "https://www.12306.cn/"),
        ["rdap_domain_lookup"] = new("rdap_domain_lookup", "域名 RDAP", "https://rdap.org/domain/{value}", "RDAP", "https://www.iana.org/rdap"),
        ["rdap_ip_lookup"] = new("rdap_ip_lookup", "IP/ASN RDAP", "https://rdap.org/ip/{value}", "RDAP", "https://www.iana.org/rdap"),
        ["http_diagnostic"] = new("http_diagnostic", "HTTP 诊断", "{value}", "目标站点", "about:blank", false),
        ["ai_latest_news"] = new("ai_latest_news", "AI 全网最新资讯", AiLatestNewsBase, "PearAPI AI News", PearApiBase, true, ApiSourceVisibility.SensitivePrivate),
        ["city_route_query"] = new("city_route_query", "城际路线查询", CityRouteBase, "PearAPI City Travel Routes", PearApiBase, true, ApiSourceVisibility.SensitivePrivate)
    };

    public static bool TryResolve(string id, string input, out ApiEndpoint endpoint, out Uri uri)
    {
        endpoint = default!;
        uri = default!;
        if (!Endpoints.TryGetValue(id, out var match))
        {
            return false;
        }

        switch (id.ToLowerInvariant())
        {
            case "hotboard":
                return ResolveDailyHot(match, input, out endpoint, out uri);
            case "baidu_hot":
            case "bili_hot":
            case "zhihu_hot":
                return ResolveDailyHot(match, string.IsNullOrWhiteSpace(input) ? DailyHotShortcuts[id] : input, out endpoint, out uri);
            case "history_today":
                return ResolveHistoryToday(match, input, out endpoint, out uri);
            case "ai_latest_news":
                return ResolveAiLatestNews(match, input, out endpoint, out uri);
            case "city_route_query":
                return ResolveCityRoute(match, input, out endpoint, out uri);
            case "movie_box_office":
                endpoint = match;
                uri = new Uri(match.UriTemplate);
                return true;
            case "dns_query":
                return ResolveDnsQuery(match, input, out endpoint, out uri);
        }

        var fallback = id switch
        {
            "weather" => "北京",
            "history_today" => DateTime.Today.ToString("MM-dd"),
            "dns_query" => "example.com",
            "domain_price" or "rdap_domain_lookup" => "example.com",
            "rdap_ip_lookup" or "ip_info" or "ip_lookup" => "8.8.8.8",
            "wx_domain_check" or "http_diagnostic" => "https://example.com",
            "qq_avatar" => "10000",
            "qq_profile" => "10000",
            _ => string.Empty
        };
        var value = string.IsNullOrWhiteSpace(input) ? fallback : input.Trim();
        if (id.Equals("history_today", StringComparison.OrdinalIgnoreCase))
        {
            value = NormalizeOnThisDay(value);
        }

        if (string.IsNullOrWhiteSpace(value) && match.UriTemplate.Contains("{value}", StringComparison.Ordinal))
        {
            value = "example.com";
        }

        var encodedValue = id.Equals("http_diagnostic", StringComparison.OrdinalIgnoreCase) ||
            id.Equals("history_today", StringComparison.OrdinalIgnoreCase)
            ? value
            : Uri.EscapeDataString(value);
        var rawUri = match.UriTemplate.Replace("{value}", encodedValue, StringComparison.Ordinal);
        if (id.Equals("http_diagnostic", StringComparison.OrdinalIgnoreCase) &&
            !rawUri.StartsWith("http://", StringComparison.OrdinalIgnoreCase) &&
            !rawUri.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
        {
            rawUri = "https://" + rawUri;
        }

        if (!Uri.TryCreate(rawUri, UriKind.Absolute, out var parsedUri))
        {
            return false;
        }

        endpoint = match;
        uri = parsedUri;
        return true;
    }

    public static bool TryGet(string id, out ApiEndpoint endpoint)
    {
        return Endpoints.TryGetValue(id, out endpoint!);
    }

    public static IReadOnlyList<ApiEndpoint> All => Endpoints.Values.ToList();

    private static bool ResolveDailyHot(ApiEndpoint match, string input, out ApiEndpoint endpoint, out Uri uri)
    {
        endpoint = match;
        var title = string.IsNullOrWhiteSpace(input) ? string.Empty : input.Trim();
        if (title.StartsWith("title=", StringComparison.OrdinalIgnoreCase))
        {
            title = title[6..];
        }

        if (string.IsNullOrWhiteSpace(title))
        {
            uri = new Uri(DailyHotBase);
            return true;
        }

        var encoded = Uri.EscapeDataString(title);
        uri = new Uri($"{DailyHotBase}?title={encoded}");
        return true;
    }

    private static bool ResolveHistoryToday(ApiEndpoint match, string input, out ApiEndpoint endpoint, out Uri uri)
    {
        endpoint = match;
        var value = string.IsNullOrWhiteSpace(input) ? DateTime.Today.ToString("MM-dd") : NormalizeOnThisDay(input);
        var encoded = Uri.EscapeDataString(value);
        uri = new Uri($"{HistoryTodayBase}&date={encoded}");
        return true;
    }

    private static bool ResolveAiLatestNews(ApiEndpoint match, string input, out ApiEndpoint endpoint, out Uri uri)
    {
        endpoint = match;
        if (string.IsNullOrWhiteSpace(input))
        {
            uri = new Uri(AiLatestNewsBase + "?key=");
            return true;
        }

        var key = input.Trim();
        if (key.StartsWith("key=", StringComparison.OrdinalIgnoreCase))
        {
            key = key[4..];
        }

        uri = new Uri($"{AiLatestNewsBase}?key={Uri.EscapeDataString(key)}");
        return true;
    }

    private static bool ResolveCityRoute(ApiEndpoint match, string input, out ApiEndpoint endpoint, out Uri uri)
    {
        endpoint = match;
        var (from, to) = ParseCityRouteInput(input);
        var fromPart = Uri.EscapeDataString(from);
        var toPart = Uri.EscapeDataString(to);
        uri = new Uri($"{CityRouteBase}?from={fromPart}&to={toPart}");
        return true;
    }

    private static bool ResolveDnsQuery(ApiEndpoint match, string input, out ApiEndpoint endpoint, out Uri uri)
    {
        var parts = input.Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
        var name = parts.ElementAtOrDefault(0);
        var type = parts.ElementAtOrDefault(1);
        var value = string.IsNullOrWhiteSpace(name) ? "example.com" : name;
        type = string.IsNullOrWhiteSpace(type) ? "A" : type.ToUpperInvariant();
        endpoint = match;
        uri = new Uri($"https://dns.google/resolve?name={Uri.EscapeDataString(value)}&type={Uri.EscapeDataString(type)}");
        return true;
    }

    private static (string From, string To) ParseCityRouteInput(string input)
    {
        var value = input.Replace("\r\n", "\n").Trim();
        if (value.Contains("->", StringComparison.Ordinal))
        {
            var parts = value.Split("->", 2, StringSplitOptions.TrimEntries);
            return (parts.ElementAtOrDefault(0) ?? "广州", parts.ElementAtOrDefault(1) ?? "深圳");
        }

        var lines = value.Split('\n', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
        if (lines.Length >= 2)
        {
            return (lines[0], lines[1]);
        }

        var tokens = value.Split(new[] { ' ', ',', ';', '|', '\t' }, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
        if (tokens.Length >= 2)
        {
            return (tokens[0], tokens[1]);
        }

        return ("广州", "深圳");
    }

    private static string NormalizeOnThisDay(string input)
    {
        if (DateTime.TryParse(input, out var date))
        {
            return $"{date:MM-dd}";
        }

        var trimmed = input.Trim().Replace('/', '-');
        var parts = trimmed.Split('-', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
        if (parts.Length >= 2 &&
            int.TryParse(parts[^2], out var month) &&
            int.TryParse(parts[^1], out var day))
        {
            return $"{month:00}-{day:00}";
        }

        return $"{DateTime.Today:MM-dd}";
    }
}
