use indexed_valued_enums_derive::{EnumIndexed, EnumValuedFromCSV};

/// Enum with every planet of the solar system.
///
/// We mark it with ``#[EnumIndex]`` so we can get the following methods:
///
/// - ``const Planet::variant_index(&self) -> usize``: Gets the index of a variant,
/// for example, [Planet::Earth] is the third variant, so it's index is 2.
///
/// - ``const Planet::variant_name(&self) -> &'static str``: Gets the name of a variant,
/// for example, [Planet::Earth] would return ``"Earth"``.
///
/// - ``const Planet::from_variant_index -> Option<Planet>``: Gets the variant matching
/// said index, for example, 2 would return ``Some(Planet::Earth)``.
///
/// - ``const Planet::from_variant_name -> Option<Planet>``: Gets the variant matching
/// said name, for example, "Earth" would return ``Some(Planet::Earth)``, but it is preferable
/// to use [Planet::from_variant_index] rather than [Planet::from_variant_name], as that one
/// is O(1) and this one is O(N).
#[EnumIndexed]
#[derive(PartialEq, Debug, EnumValuedFromCSV)]
#[EnumValuedFromCSV(pub in_crate "examples/planets.csv")]
pub enum Planet{
    Mercury,
    Venus,
    Earth,
    Mars,
    Jupiter,
    Saturn,
    Uranus,
    Neptune,
}


pub fn main() {
    // Iterate over every variant.
    Planet::VARIANTS.iter().for_each(|planet|{
        let name = planet.variant_name();
        let gravity = planet.gravity();
        let description = planet.description();
        println!("The planet {name} has a gravity of {gravity} and description: {description}");
    });

    // Get a variant from its name.
    let earth = Planet::from_variant_name("Earth").unwrap();
    let name = earth.variant_name();
    let gravity = earth.gravity();
    println!("The planet {name} is our home, and it has a gravity of {gravity}");

    // Get a variant's index.
    let earth_index_in_enum = Planet::Earth.variant_index();
    println!("Planet Earth has and index of {earth_index_in_enum}");

    // Get a variant's from its index.
    // In this case, the planet earth is the variant with index 2.
    let earth = Planet::from_variant_index(earth_index_in_enum).unwrap();
    let earth_from_raw_index = Planet::from_variant_index(2).unwrap();

    assert_eq!(earth, Planet::Earth);
    assert_eq!(earth_from_raw_index, Planet::Earth);

    // Get a planet out of its gravity.
    let planet_with_9_8_gravity = Planet::from_gravity(&9.8).unwrap();

    println!("The planet with 9.8 gravity is {}", planet_with_9_8_gravity.variant_name());
}