use std::path::Path;

use anyhow::Context;

use super::{Ecosystem, Package};

/// Parse Cargo.lock (supports v1, v2, and v3 formats).
/// All formats use the same [[package]] table structure.
pub fn parse(path: &Path) -> anyhow::Result<Vec<Package>> {
    let content = std::fs::read_to_string(path).context("Failed to read Cargo.lock")?;
    let parsed: toml::Value = toml::from_str(&content).context("Failed to parse Cargo.lock")?;

    let packages = parsed
        .get("package")
        .and_then(|p| p.as_array())
        .map(|arr| {
            arr.iter()
                .filter_map(|entry| {
                    let name = entry.get("name")?.as_str()?.to_string();
                    let version = entry.get("version")?.as_str()?.to_string();
                    Some(Package {
                        name,
                        version,
                        ecosystem: Ecosystem::CratesIo,
                    })
                })
                .collect()
        })
        .unwrap_or_default();

    Ok(packages)
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::fs;
    use tempfile::TempDir;

    #[test]
    fn test_parse_cargo_lock_v3() {
        let dir = TempDir::new().unwrap();
        let lock = dir.path().join("Cargo.lock");
        fs::write(
            &lock,
            r#"# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3

[[package]]
name = "serde"
version = "1.0.200"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "regex"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
"#,
        )
        .unwrap();

        let packages = parse(&lock).unwrap();
        assert_eq!(packages.len(), 2);
        assert_eq!(packages[0].name, "serde");
        assert_eq!(packages[0].version, "1.0.200");
        assert_eq!(packages[0].ecosystem, Ecosystem::CratesIo);
        assert_eq!(packages[1].name, "regex");
    }

    #[test]
    fn test_parse_cargo_lock_v1() {
        let dir = TempDir::new().unwrap();
        let lock = dir.path().join("Cargo.lock");
        fs::write(
            &lock,
            r#"[[package]]
name = "my-crate"
version = "0.1.0"

[[package]]
name = "dep"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
"#,
        )
        .unwrap();

        let packages = parse(&lock).unwrap();
        assert_eq!(packages.len(), 2);
    }
}
