use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub enum AchievementId {
    FirstSave,
    Streak7,
    Streak30,
    Million,
    HundredM,
    Billion,
    AllModes,
    Rate90,
    Bugs10,
    Dragon,
    Lv50,
    Mythic,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Achievement {
    pub id: AchievementId,
    pub name: &'static str,
    pub icon: &'static str,
    pub description: &'static str,
}

impl Achievement {
    pub fn badge(&self) -> String {
        format!("{} {}", self.icon, self.name)
    }
}

const ALL: &[Achievement] = &[
    Achievement {
        id: AchievementId::FirstSave,
        name: "First Blood",
        icon: "🩸",
        description: "Saved your first token",
    },
    Achievement {
        id: AchievementId::Streak7,
        name: "Week Warrior",
        icon: "🔥",
        description: "7-day usage streak",
    },
    Achievement {
        id: AchievementId::Streak30,
        name: "Monthly Master",
        icon: "👑",
        description: "30-day usage streak",
    },
    Achievement {
        id: AchievementId::Million,
        name: "Millionaire",
        icon: "💰",
        description: "Saved 1M tokens",
    },
    Achievement {
        id: AchievementId::HundredM,
        name: "Centurion",
        icon: "🏛️",
        description: "Saved 100M tokens",
    },
    Achievement {
        id: AchievementId::Billion,
        name: "Billionaire",
        icon: "💎",
        description: "Saved 1B tokens",
    },
    Achievement {
        id: AchievementId::AllModes,
        name: "Polyglot",
        icon: "📚",
        description: "Used all read modes",
    },
    Achievement {
        id: AchievementId::Rate90,
        name: "Efficiency Expert",
        icon: "⚡",
        description: "90%+ compression rate",
    },
    Achievement {
        id: AchievementId::Bugs10,
        name: "Bug Squasher",
        icon: "🐛",
        description: "Prevented 10 bugs",
    },
    Achievement {
        id: AchievementId::Dragon,
        name: "Dragon Tamer",
        icon: "🐉",
        description: "Mixed-language project",
    },
    Achievement {
        id: AchievementId::Lv50,
        name: "Half Century",
        icon: "🎯",
        description: "Reached Level 50",
    },
    Achievement {
        id: AchievementId::Mythic,
        name: "Ascended",
        icon: "✨",
        description: "Reached Mythic evolution",
    },
];

pub fn catalog() -> &'static [Achievement] {
    ALL
}

pub fn check_unlocked(
    tokens_saved: u64,
    streak_days: u32,
    bugs_prevented: u64,
    compression_pct: u8,
    level: u32,
    species: &super::types::Species,
    mode_count: usize,
    evolution: &super::evolution::EvolutionStage,
) -> Vec<&'static Achievement> {
    let mut unlocked = Vec::new();
    for a in ALL {
        let earned = match a.id {
            AchievementId::FirstSave => tokens_saved > 0,
            AchievementId::Streak7 => streak_days >= 7,
            AchievementId::Streak30 => streak_days >= 30,
            AchievementId::Million => tokens_saved >= 1_000_000,
            AchievementId::HundredM => tokens_saved >= 100_000_000,
            AchievementId::Billion => tokens_saved >= 1_000_000_000,
            AchievementId::AllModes => mode_count >= 8,
            AchievementId::Rate90 => compression_pct >= 90,
            AchievementId::Bugs10 => bugs_prevented >= 10,
            AchievementId::Dragon => *species == super::types::Species::Dragon,
            AchievementId::Lv50 => level >= 50,
            AchievementId::Mythic => *evolution == super::evolution::EvolutionStage::Mythic,
        };
        if earned {
            unlocked.push(a);
        }
    }
    unlocked
}

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

    #[test]
    fn first_save_unlocks() {
        let r = check_unlocked(
            1,
            0,
            0,
            0,
            0,
            &super::super::types::Species::Egg,
            0,
            &super::super::evolution::EvolutionStage::Egg,
        );
        assert!(r.iter().any(|a| a.id == AchievementId::FirstSave));
    }

    #[test]
    fn nothing_at_zero() {
        let r = check_unlocked(
            0,
            0,
            0,
            0,
            0,
            &super::super::types::Species::Egg,
            0,
            &super::super::evolution::EvolutionStage::Egg,
        );
        assert!(r.is_empty());
    }

    #[test]
    fn mythic_unlocks_at_mythic_stage() {
        let r = check_unlocked(
            500_000_000,
            40,
            20,
            95,
            70,
            &super::super::types::Species::Crab,
            8,
            &super::super::evolution::EvolutionStage::Mythic,
        );
        assert!(r.iter().any(|a| a.id == AchievementId::Mythic));
        assert!(r.iter().any(|a| a.id == AchievementId::HundredM));
        assert!(r.iter().any(|a| a.id == AchievementId::Lv50));
    }

    #[test]
    fn catalog_has_12_entries() {
        assert_eq!(catalog().len(), 12);
    }
}
