use anyhow::Result;
use serde::Deserialize;

#[derive(Deserialize)]
struct CratesIoResponse {
    #[serde(rename = "crate")]
    crate_info: CrateInfo,
}

#[derive(Deserialize)]
struct CrateInfo {
    max_version: String,
}

pub async fn check_for_updates() {
    let current_version = env!("CARGO_PKG_VERSION");

    match fetch_latest_version().await {
        Ok(latest_version) => {
            if is_newer_version(&latest_version, current_version) {
                println!("╔═══════════════════════════════════════════════════════════╗");
                println!("║  🎉 A new version of doqium-cli is available!             ║");
                println!("║                                                           ║");
                println!("║  Current: {:<47} ║", current_version);
                println!("║  Latest:  {:<47} ║", latest_version);
                println!("║                                                           ║");
                println!("║  Update with:                                             ║");
                println!("║  cargo install doqium-cli                                 ║");
                println!("╚═══════════════════════════════════════════════════════════╝");
                println!();
            }
        }
        Err(_) => {
            // Silently ignore errors - version check is not critical
        }
    }
}

async fn fetch_latest_version() -> Result<String> {
    let client = reqwest::Client::builder()
        .timeout(std::time::Duration::from_secs(3))
        .build()?;

    let response: CratesIoResponse = client
        .get("https://crates.io/api/v1/crates/doqium-cli")
        .header(
            "User-Agent",
            format!("doqium-cli/{}", env!("CARGO_PKG_VERSION")),
        )
        .send()
        .await?
        .json()
        .await?;

    Ok(response.crate_info.max_version)
}

fn is_newer_version(latest: &str, current: &str) -> bool {
    let parse_version = |v: &str| -> Vec<u32> {
        v.split('.')
            .filter_map(|part| part.parse::<u32>().ok())
            .collect()
    };

    let latest_parts = parse_version(latest);
    let current_parts = parse_version(current);

    for (l, c) in latest_parts.iter().zip(current_parts.iter()) {
        if l > c {
            return true;
        } else if l < c {
            return false;
        }
    }

    latest_parts.len() > current_parts.len()
}

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

    #[test]
    fn test_is_newer_version() {
        assert!(is_newer_version("1.0.1", "1.0.0"));
        assert!(is_newer_version("1.1.0", "1.0.0"));
        assert!(is_newer_version("2.0.0", "1.0.0"));
        assert!(!is_newer_version("1.0.0", "1.0.0"));
        assert!(!is_newer_version("1.0.0", "1.0.1"));
        assert!(!is_newer_version("1.0.0", "1.1.0"));
    }
}
