use data::tables::AvatarBaseID;
use proto::{AvatarBin, AvatarInfo, AvatarSkillInfo};

use crate::logic::item::ItemUID;

use super::AvatarSkill;

pub const AVATAR_TALENT_COUNT: usize = 6;
pub struct Avatar {
    pub template_id: AvatarBaseID,
    pub level: u32,
    pub exp: u32,
    pub star: u32,
    pub rank: u32,
    pub unlocked_talent_num: u32,
    pub weapon_uid: Option<ItemUID>,
    pub skill_list: Vec<AvatarSkill>,
    pub talent_switch: [bool; AVATAR_TALENT_COUNT],
}

impl Avatar {
    pub fn new(template_id: AvatarBaseID) -> Self {
        Self {
            template_id,
            level: 60,
            exp: 0,
            star: 0,
            rank: 6,
            unlocked_talent_num: 6,
            weapon_uid: None,
            skill_list: (0..=6)
                .map(|st| AvatarSkill {
                    skill_type: st,
                    level: 1,
                })
                .collect(),
            talent_switch: [true; AVATAR_TALENT_COUNT],
        }
    }

    pub fn from_bin(bin: AvatarBin) -> Self {
        Self {
            template_id: AvatarBaseID::new_unchecked(bin.template_id),
            level: bin.level,
            exp: bin.exp,
            star: bin.star,
            rank: bin.rank,
            unlocked_talent_num: bin.unlocked_talent_num,
            weapon_uid: (bin.weapon_uid != 0).then_some(bin.weapon_uid.into()),
            skill_list: bin
                .avatar_skill_list
                .into_iter()
                .map(AvatarSkill::from_bin)
                .collect(),
            talent_switch: bin
                .talent_switch_list
                .try_into()
                .unwrap_or([false; AVATAR_TALENT_COUNT]),
        }
    }

    pub fn to_bin(&self) -> AvatarBin {
        AvatarBin {
            template_id: self.template_id.value(),
            exp: self.exp,
            level: self.level,
            star: self.star,
            rank: self.rank,
            unlocked_talent_num: self.unlocked_talent_num,
            weapon_uid: self.weapon_uid.map(|u| u.value()).unwrap_or_default(),
            avatar_skill_list: self.skill_list.iter().map(AvatarSkill::to_bin).collect(),
            talent_switch_list: self.talent_switch.to_vec(),
        }
    }

    pub fn to_client(&self) -> AvatarInfo {
        AvatarInfo {
            template_id: self.template_id.value(),
            level: self.level,
            skill_list: self
                .skill_list
                .iter()
                .map(|s| AvatarSkillInfo {
                    skill_type: s.skill_type,
                    level: s.level,
                })
                .collect(),
            exp: self.exp,
            rank: self.rank,
            talent_switch_list: self.talent_switch.to_vec(),
            unlocked_talent_num: self.unlocked_talent_num,
            cur_weapon_uid: self.weapon_uid.map(|u| u.value()).unwrap_or_default(),
            ..Default::default()
        }
    }
}
