//! Parse and generate Gazelle tracker torrent URLs.

use crate::prelude::*;

/// Match group URL: `/torrents.php?id={group}&torrentid={torrent}`.
static GROUP_URL_REGEX: LazyLock<Regex> = LazyLock::new(|| {
    Regex::new(r"/torrents\.php\?id=(\d+)&torrentid=(\d+)(#torrent\d+)?$")
        .expect("regex should compile")
});
/// Match direct torrent URL: `/torrents.php?torrentid={torrent}`.
static TORRENT_URL_REGEX: LazyLock<Regex> = LazyLock::new(|| {
    Regex::new(r"/torrents\.php\?torrentid=(\d+)(#torrent\d+)?$").expect("regex should compile")
});

/// Extract torrent ID from a tracker URL.
pub fn get_torrent_id_from_url(url: &str) -> Result<u32, IdProviderError> {
    get_torrent_id_from_group_url(url)
        .or_else(|| get_torrent_id_from_torrent_url(url))
        .ok_or(IdProviderError::UrlInvalid)
}

/// Extract torrent ID from a group URL with torrentid parameter.
#[must_use]
pub fn get_torrent_id_from_group_url(url: &str) -> Option<u32> {
    let id = GROUP_URL_REGEX
        .captures(url)?
        .get(2)?
        .as_str()
        .parse::<u32>()
        .expect("Number can be parsed");
    Some(id)
}

/// Extract torrent ID from a direct torrent URL.
#[must_use]
pub fn get_torrent_id_from_torrent_url(url: &str) -> Option<u32> {
    let id = TORRENT_URL_REGEX
        .captures(url)?
        .get(1)?
        .as_str()
        .parse::<u32>()
        .expect("Number can be parsed");
    Some(id)
}

/// Extract the group ID from a torrent group URL.
#[must_use]
#[cfg(test)]
pub fn get_group_id_from_url(url: &str) -> Option<u32> {
    let id = GROUP_URL_REGEX
        .captures(url)?
        .get(1)?
        .as_str()
        .parse::<u32>()
        .expect("Number can be parsed");
    Some(id)
}

/// Identify the [`Indexer`] from a tracker URL.
///
/// - URLs starting with `https://redacted.sh` or `https://redacted.ch` map to [`Indexer::Red`]
/// - URLs starting with `https://orpheus.network` map to [`Indexer::Ops`]
/// - Returns `None` for unrecognized URLs
#[must_use]
pub fn get_indexer_from_url(url: &str) -> Option<Indexer> {
    if url.starts_with(RED_URL) || url.starts_with(RED_URL_CH) {
        Some(Indexer::Red)
    } else if url.starts_with(OPS_URL) {
        Some(Indexer::Ops)
    } else {
        None
    }
}

/// Generate a permalink URL for a torrent including the group ID.
#[must_use]
pub fn get_permalink(base: &str, group_id: u32, torrent_id: u32) -> String {
    format!(r"{base}/torrents.php?id={group_id}&torrentid={torrent_id}#torrent{torrent_id}")
}

/// Generate a permalink URL for a torrent without the group ID.
#[must_use]
pub fn get_torrent_permalink(base: &str, torrent_id: u32) -> String {
    format!(r"{base}/torrents.php?torrentid={torrent_id}")
}

/// Generate the URL for the tracker's report create page.
#[must_use]
pub fn get_report_url(base: &str, torrent_id: u32) -> String {
    format!("{base}/reportsv2.php?action=report&id={torrent_id}")
}
