Skip to content
use serde::{Deserialize, Serialize};

#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct PokemonMove {
    pub name: String,
    pub level: i32,
    pub method: String,
}

impl PokemonMove {
    #[must_use]
    pub fn formatted_name(&self) -> String {
        self.name.replace('-', " ")
    }

    #[must_use]
    pub fn formatted_method(&self) -> String {
        match self.method.as_str() {
            "level-up" => {
                if self.level > 0 {
                    format!("Level {}", self.level)
                } else {
                    "Evolution / Start".to_string()
                }
            }
            "machine" => "TM / HM".to_string(),
            "tutor" => "Move Tutor".to_string(),
            "egg" => "Egg Move".to_string(),
            other => other.to_string(),
        }
    }
}

#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct Pokemon {
    pub id: i32,
    pub name: String,
    pub display_name: String,
    pub types: Vec<String>,
    pub hp: i32,
    pub attack: i32,
    pub defense: i32,
    pub sp_attack: i32,
    pub sp_defense: i32,
    pub speed: i32,
    pub height: i32,
    pub weight: i32,
    pub sprite_url: String,
    pub artwork_url: String,
    pub genus: String,
    pub description: String,
    pub moves: Vec<PokemonMove>,
}

impl Pokemon {
    #[must_use]
    pub fn formatted_id(&self) -> String {
        format!("#{:03}", self.id)
    }

    #[must_use]
    pub fn total_stats(&self) -> i32 {
        self.hp + self.attack + self.defense + self.sp_attack + self.sp_defense + self.speed
    }

    #[must_use]
    pub fn height_meters(&self) -> String {
        #[allow(clippy::cast_precision_loss)]
        let m = f64::from(self.height) / 10.0;
        format!("{m:.1} m")
    }

    #[must_use]
    pub fn weight_kg(&self) -> String {
        #[allow(clippy::cast_precision_loss)]
        let kg = f64::from(self.weight) / 10.0;
        format!("{kg:.1} kg")
    }

    #[must_use]
    pub fn level_up_moves(&self) -> Vec<&PokemonMove> {
        let mut list: Vec<&PokemonMove> = self
            .moves
            .iter()
            .filter(|m| m.method == "level-up")
            .collect();
        list.sort_by_key(|m| m.level);
        list
    }

    #[must_use]
    pub fn machine_tutor_moves(&self) -> Vec<&PokemonMove> {
        let mut list: Vec<&PokemonMove> = self
            .moves
            .iter()
            .filter(|m| m.method != "level-up")
            .collect();
        list.sort_by(|a, b| a.name.cmp(&b.name));
        list
    }
}