/// Query parameters that change per request (timestamps, signatures, nonces).
/// These should be stripped when normalizing URLs to patterns.
pub const VOLATILE_PARAMS: &[&str] = &[
    "w_rid",
    "wts",
    "_",
    "callback",
    "timestamp",
    "t",
    "nonce",
    "sign",
];

/// Query parameters that indicate a search/query capability.
pub const SEARCH_PARAMS: &[&str] = &[
    "q",
    "query",
    "keyword",
    "search",
    "wd",
    "kw",
    "search_query",
    "w",
];

/// Query parameters that indicate pagination support.
pub const PAGINATION_PARAMS: &[&str] = &["page", "pn", "offset", "cursor", "next", "page_num"];

/// Query parameters that indicate a configurable result limit.
pub const LIMIT_PARAMS: &[&str] = &[
    "limit",
    "count",
    "size",
    "per_page",
    "page_size",
    "ps",
    "num",
];

/// Mapping from semantic role to field name fragments that indicate that role.
pub const FIELD_ROLES: &[(&str, &[&str])] = &[
    ("title", &["title", "name", "headline", "subject"]),
    ("url", &["url", "link", "href", "uri"]),
    (
        "author",
        &["author", "user", "creator", "owner", "nickname", "username"],
    ),
    (
        "score",
        &["score", "likes", "views", "count", "hot", "rank", "digg"],
    ),
    (
        "time",
        &["time", "date", "created", "updated", "publish", "timestamp"],
    ),
    ("id", &["id", "uid", "vid", "mid", "aid", "cid"]),
    (
        "cover",
        &["cover", "pic", "thumb", "image", "avatar", "img"],
    ),
    (
        "category",
        &["category", "tag", "type", "channel", "genre", "topic"],
    ),
];

/// Keywords in URLs that indicate noise (tracking, analytics, static assets).
pub const NOISE_KEYWORDS: &[&str] = &[
    "analytics",
    "tracking",
    "pixel",
    "beacon",
    "log",
    "report",
    "collect",
    ".js",
    ".css",
    ".png",
    ".jpg",
    ".gif",
    ".svg",
    ".woff",
    ".ttf",
    ".ico",
    "favicon",
    "sw.js",
    "service-worker",
    "manifest.json",
    "sockjs",
    "websocket",
    "heartbeat",
    "ping",
    "health",
];

/// Returns `true` if the URL looks like noise (tracking, static assets, etc.).
pub fn is_noise_url(url: &str) -> bool {
    let lower = url.to_lowercase();
    NOISE_KEYWORDS.iter().any(|kw| lower.contains(kw))
}

/// Aliases mapping user-provided goal strings to canonical capability names.
pub const GOAL_ALIASES: &[(&str, &str)] = &[
    ("hot", "hot"),
    ("hotlist", "hot"),
    ("trending", "hot"),
    ("rank", "hot"),
    ("ranking", "hot"),
    ("search", "search"),
    ("query", "search"),
    ("find", "search"),
    ("lookup", "search"),
    ("feed", "feed"),
    ("timeline", "feed"),
    ("stream", "feed"),
    ("detail", "detail"),
    ("info", "detail"),
    ("item", "detail"),
    ("profile", "detail"),
    ("recommend", "recommend"),
    ("suggestion", "recommend"),
    ("related", "recommend"),
    ("comment", "comment"),
    ("reply", "comment"),
    ("comments", "comment"),
    ("download", "download"),
    ("save", "download"),
    ("export", "download"),
];

/// Normalize a user-provided goal string to a canonical capability name.
pub fn normalize_goal(goal: &str) -> Option<&'static str> {
    let lower = goal.to_lowercase();
    GOAL_ALIASES
        .iter()
        .find(|(alias, _)| *alias == lower.as_str())
        .map(|(_, canonical)| *canonical)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_is_noise_url_tracking() {
        assert!(is_noise_url("https://example.com/analytics/collect?v=1"));
        assert!(is_noise_url("https://cdn.example.com/style.css"));
        assert!(is_noise_url("https://example.com/favicon.ico"));
    }

    #[test]
    fn test_is_noise_url_not_noise() {
        assert!(!is_noise_url("https://api.example.com/v1/hot"));
        assert!(!is_noise_url("https://example.com/api/search?q=rust"));
    }

    #[test]
    fn test_normalize_goal_known() {
        assert_eq!(normalize_goal("hot"), Some("hot"));
        assert_eq!(normalize_goal("trending"), Some("hot"));
        assert_eq!(normalize_goal("search"), Some("search"));
        assert_eq!(normalize_goal("query"), Some("search"));
        assert_eq!(normalize_goal("timeline"), Some("feed"));
        assert_eq!(normalize_goal("download"), Some("download"));
    }

    #[test]
    fn test_normalize_goal_case_insensitive() {
        assert_eq!(normalize_goal("HOT"), Some("hot"));
        assert_eq!(normalize_goal("Trending"), Some("hot"));
        assert_eq!(normalize_goal("SEARCH"), Some("search"));
    }

    #[test]
    fn test_normalize_goal_unknown() {
        assert_eq!(normalize_goal("foobar"), None);
        assert_eq!(normalize_goal(""), None);
    }
}
