use std::{
    cell::RefCell,
    collections::{BTreeMap, HashMap, HashSet},
    rc::{Rc, Weak},
};

use common::tools::time_utils;
use data::iter_avatar_data;
use proto::{
    AvatarDataNotify, AvatarTeamBin, AvatarTeamUpdateNotify, PlayerAvatarCompBin, Retcode,
    VisionType,
};
use tokio::sync::OnceCell;

use crate::{
    creature::{Creature, LifeState},
    entity::{Entity, VisionContext},
    player::Player,
    scene::Scene,
};

use super::{Avatar, AvatarTeam, AvatarTeamEntity, FormalAvatar, MirrorAvatar, TrialAvatar};

#[derive(Default)]
pub struct PlayerAvatarComp {
    player: OnceCell<Weak<Player>>,
    pub avatar_map: BTreeMap<u64, Rc<RefCell<Avatar>>>,
    pub trial_avatar_guid_set: HashSet<u64>,
    pub temp_avatar_guid_set: HashSet<u64>,
    pub avatar_team_map: BTreeMap<u32, RefCell<AvatarTeam>>,
    pub cur_avatar_team_id: u32,
    pub last_change_avatar_time_ms: u64,
    pub is_spring_auto_use: bool,
    pub spring_auto_use_percent: u32,
    pub last_background_avatar_recover_time: u32,
    pub is_flyable: bool,
    pub is_transferable: bool,
    pub last_avatar_guid: u64,
    pub choose_avatar_guid: u64,
    pub die_type: u32,
    pub owned_flycloak_set: HashSet<u32>,
    pub owned_costume_set: HashSet<u32>,
    pub team_entity: Weak<RefCell<AvatarTeamEntity>>,
    cur_avatar_ptr: RefCell<Weak<RefCell<Avatar>>>,
}

impl PlayerAvatarComp {
    const INIT_TEAM_ID: u32 = 1;
    const TRAVELER_MALE_ID: u32 = 10000005;
    const TRAVELER_FEMALE_ID: u32 = 10000007;

    pub fn set_player(&self, player: Rc<Player>) {
        self.player.set(Rc::downgrade(&player)).unwrap();
    }

    pub fn player(&self) -> Option<Rc<Player>> {
        self.player.get().map(|p| p.upgrade())?
    }

    pub fn init(&mut self) {
        if self.get_avatar_count() != 0 {
            if self.choose_avatar_guid != 0 {
                let player = self.player().unwrap();
                for (_, avatar) in self.avatar_map.iter_mut() {
                    let mut avatar = avatar.borrow_mut();
                    avatar.base_avatar_mut().set_player(player.clone());
                    avatar.init();
                }

                if self.avatar_team_map.is_empty() {
                    self.avatar_team_map.insert(
                        Self::INIT_TEAM_ID,
                        RefCell::new(AvatarTeam {
                            avatar_vec: vec![self.choose_avatar_guid],
                            last_cur_avatar_guid: 0,
                            team_name: String::new(),
                        }),
                    );

                    tracing::warn!(
                        "avatar_team_map empty player_uid: {}",
                        self.player().unwrap().uid
                    );
                }

                if !self.avatar_team_map.contains_key(&self.cur_avatar_team_id) {
                    tracing::warn!(
                        "cur_avatar_team_id:{} not in team_map player_uid: {}",
                        self.cur_avatar_team_id,
                        self.player().unwrap().uid
                    );

                    self.cur_avatar_team_id = *self.avatar_team_map.iter().next().unwrap().0;
                }

                let mut cur_team = self
                    .avatar_team_map
                    .get(&self.cur_avatar_team_id)
                    .unwrap()
                    .borrow_mut();
                if cur_team.avatar_vec.is_empty() {
                    cur_team.avatar_vec.push(self.choose_avatar_guid);
                    tracing::warn!(
                        "cur_avatar_team avatar empty player_uid: {} cur_avatar_team_id: {}",
                        self.player().unwrap().uid,
                        self.cur_avatar_team_id
                    );
                }

                if !cur_team.avatar_vec.contains(&cur_team.last_cur_avatar_guid) {
                    cur_team.last_cur_avatar_guid = cur_team.avatar_vec[0];
                }
            } else {
                tracing::error!(
                    "choose_avatar_guid = 0 player_uid: {}",
                    self.player().unwrap().uid
                );
            }
        }
    }

    pub fn check_avatar_guid_vec_all_formal(&self, guid_vec: &[u64]) -> Result<(), Retcode> {
        for guid in guid_vec {
            if self.find_formal_avatar(*guid).is_none() {
                tracing::warn!("find_formal_avatar failed, avatar_guid: {guid}");
                return Err(Retcode::RetFail);
            }
        }

        Ok(())
    }

    pub fn get_cur_avatar_team_with_temp_avatar(&self) -> Vec<u64> {
        let cur_team = self
            .avatar_team_map
            .get(&self.cur_avatar_team_id)
            .unwrap()
            .borrow();
        let mut result = cur_team.avatar_vec.clone();
        result.extend(self.trial_avatar_guid_set.iter().collect::<Vec<_>>());

        result
    }

    pub fn get_cur_avatar_team_vec(&self) -> Vec<Rc<RefCell<Avatar>>> {
        let cur_avatar_team = self.avatar_team_map.get(&self.cur_avatar_team_id).unwrap();
        cur_avatar_team
            .borrow()
            .avatar_vec
            .iter()
            .map(|guid| self.avatar_map.get(guid).map(|a| a.clone()))
            .flatten()
            .collect()
    }

    pub fn get_my_avatar_team_in_scene_team(&self) -> Vec<u64> {
        let player = self.player().unwrap();
        let cur_world = player
            .player_scene_comp
            .borrow()
            .get_cur_scene()
            .unwrap()
            .borrow()
            .base()
            .cur_world_wtr
            .upgrade()
            .unwrap();

        let cur_world = cur_world.borrow();
        cur_world
            .scene_team
            .get_avatar_guid_vec(player.uid)
            .unwrap_or_default()
    }

    pub fn is_my_avatar_in_scene_team(&self, guid: u64) -> bool {
        let guid_vec = self.get_my_avatar_team_in_scene_team();
        if !guid_vec.contains(&guid) {
            tracing::info!("guid:{guid} not in scene team, guid_vec:{guid_vec:?}");
            false
        } else {
            true
        }
    }

    pub fn set_up_avatar_team(
        &self,
        team_id: u32,
        avatar_guid_vec: &[u64],
        target_avatar_guid: u64,
    ) -> Result<(), Retcode> {
        let Some(_cur_avatar_ptr) = self.cur_avatar_ptr.borrow().upgrade() else {
            tracing::warn!("cur_avatar_ptr is None");
            return Err(Retcode::RetFail);
        };

        if let Err(ret) = self.check_avatar_team_can_set_up(team_id, avatar_guid_vec) {
            tracing::info!("check_avatar_team_can_set_up failed");
            return Err(ret);
        }

        if self.cur_avatar_team_id == team_id
            && !self.temp_avatar_guid_set.contains(&target_avatar_guid)
            && !avatar_guid_vec.contains(&target_avatar_guid)
        {
            tracing::warn!("can't find avatar in team, guid:{target_avatar_guid}");
            return Err(Retcode::RetAvatarNotExistInTeam);
        }

        if let Err(ret) = self.check_change_cur_avatar(target_avatar_guid) {
            tracing::info!("check_change_cur_avatar failed, guid:{target_avatar_guid}");
            return Err(ret);
        }

        self.avatar_team_map
            .get(&team_id)
            .unwrap()
            .borrow_mut()
            .avatar_vec = avatar_guid_vec.to_vec();
        self.notify_avatar_team(team_id);

        if self.cur_avatar_team_id == team_id {
            self.sync_cur_avatar_team_to_scene_team(target_avatar_guid)?;
        }

        Ok(())
    }

    fn notify_avatar_team(&self, team_id: u32) {
        let avatar_team = self.avatar_team_map.get(&team_id).unwrap().borrow();

        self.player().unwrap().send_proto(AvatarTeamUpdateNotify {
            temp_avatar_guid_list: self.temp_avatar_guid_set.iter().cloned().collect(),
            avatar_team_map: HashMap::from([(
                team_id,
                proto::AvatarTeam {
                    team_name: avatar_team.team_name.clone(),
                    avatar_guid_list: avatar_team.avatar_vec.clone(),
                },
            )]),
        });
    }

    fn sync_cur_avatar_team_to_scene_team(&self, target_avatar_guid: u64) -> Result<(), Retcode> {
        let cur_team = self.get_cur_avatar_team_with_temp_avatar();
        if cur_team.is_empty() {
            tracing::warn!(
                "cur_team empty, target_avatar_guid:{target_avatar_guid}, uid:{}",
                self.player().unwrap().uid
            );
            return Err(Retcode::RetFail);
        }

        let player = self.player().unwrap();
        let scene_comp = player.player_scene_comp.borrow();
        let Some(cur_scene) = scene_comp.get_cur_scene() else {
            tracing::info!(
                "get_cur_scene target_avatar_guid:{target_avatar_guid}, uid:{}",
                self.player().unwrap().uid
            );
            return Err(Retcode::RetFail);
        };
        drop(scene_comp);

        if let Err(ret) =
            self.set_scene_team_and_add_to_scene(cur_team, target_avatar_guid, cur_scene)
        {
            tracing::warn!("set_scene_team_and_add_to_scene fails");
            return Err(ret);
        }

        Ok(())
    }

    fn set_scene_team_and_add_to_scene(
        &self,
        avatar_vec: Vec<u64>,
        appear_avatar_guid: u64,
        cur_scene: Rc<RefCell<Scene>>,
    ) -> Result<(), Retcode> {
        let cur_world = cur_scene.borrow().base().cur_world_wtr.upgrade().unwrap();

        let old_team = cur_world
            .borrow()
            .scene_team
            .get_avatar_guid_vec(self.player().unwrap().uid)
            .unwrap();

        if let Err(ret) = cur_world
            .borrow_mut()
            .scene_team
            .set_player_avatar_team_and_add_to_scene(
                self.player().unwrap().uid,
                avatar_vec.clone(),
                appear_avatar_guid,
                &mut cur_scene.borrow_mut(),
                false,
            )
        {
            tracing::warn!(
                "set_player_avatar_team_and_add_to_scene fails, uid:{}",
                self.player().unwrap().uid
            );
            return Err(ret);
        }

        if appear_avatar_guid != self.get_cur_avatar().unwrap().borrow().base_avatar().guid {
            if let Err(ret) = self.change_cur_avatar(appear_avatar_guid, false) {
                tracing::warn!(
                    "change_cur_avatar fails, ret:{ret:?}, uid: {}",
                    self.player().unwrap().uid
                );
            }
        }

        cur_world.borrow().scene_team.notify_scene_team_update();
        let cur_team = cur_world
            .borrow()
            .scene_team
            .get_avatar_guid_vec(self.player().unwrap().uid)
            .unwrap();

        tracing::info!("set_scene_team_and_add_to_scene set_avatar_vec:{avatar_vec:?}, old_team:{old_team:?}, cur_team:{cur_team:?}, uid:{}", self.player().unwrap().uid);

        let scene = {
            let player = self.player().unwrap();
            let scene_comp = player.player_scene_comp.borrow();
            scene_comp.get_cur_scene().unwrap()
        };

        for guid in old_team {
            if !cur_team.contains(&guid) {
                if let Some(avatar_ptr) = self.find_avatar(guid) {
                    scene.borrow_mut().del_avatar_and_weapon_entity(avatar_ptr);
                }
            }
        }

        Ok(())
    }

    pub fn change_cur_avatar(&self, guid: u64, is_notify: bool) -> Result<(), Retcode> {
        let Some(cur_avatar_ptr) = self.cur_avatar_ptr.borrow().upgrade() else {
            tracing::error!(
                "cur_avatar_ptr is None, guid: {guid}, player: {}",
                self.player().unwrap().uid
            );
            return Err(Retcode::RetFail);
        };

        let Some(dest_avatar_ptr) = self.find_avatar(guid) else {
            tracing::error!("find_avatar fails, guid:{guid}");
            return Err(Retcode::RetFail);
        };

        {
            let mut dest_avatar = dest_avatar_ptr.borrow_mut();
            let cur_avatar = cur_avatar_ptr.borrow();

            dest_avatar.set_position(cur_avatar.position().clone());
            dest_avatar.set_rotation(cur_avatar.rotation().clone());
            dest_avatar.set_last_valid_position(cur_avatar.position().clone());
            dest_avatar.set_last_valid_rotation(cur_avatar.rotation().clone());
        }

        let scene = {
            let player = self.player().unwrap();
            let scene_comp = player.player_scene_comp.borrow();
            scene_comp.get_cur_scene().unwrap()
        };

        let vision_type = match is_notify {
            true => VisionType::VisionReplace,
            false => VisionType::VisionReplaceNoNotify,
        };

        if let Err(ret) = scene.borrow_mut().entity_disappear(
            &(cur_avatar_ptr.clone() as Rc<RefCell<dyn Entity>>),
            VisionContext::new(vision_type),
        ) {
            tracing::warn!("entity_disappear fails");
            return Err(ret);
        }

        if dest_avatar_ptr.borrow().entity_id() == 0 {
            tracing::warn!("change_cur_avatar fails. avatar entityid is 0.");
            return Err(Retcode::RetFail);
        }

        if let Err(ret) = scene.borrow_mut().entity_appear(
            &(dest_avatar_ptr.clone() as Rc<RefCell<dyn Entity>>),
            VisionContext::new(vision_type),
        ) {
            tracing::warn!("entity_appear fails");
            return Err(ret);
        }

        *self.cur_avatar_ptr.borrow_mut() = Rc::downgrade(&dest_avatar_ptr);
        self.avatar_team_map
            .get(&self.cur_avatar_team_id)
            .unwrap()
            .borrow_mut()
            .last_cur_avatar_guid = guid;

        Ok(())
    }

    pub fn check_avatar_team_can_set_up(
        &self,
        team_id: u32,
        avatar_guid_vec: &[u64],
    ) -> Result<(), Retcode> {
        if !self.avatar_team_map.contains_key(&team_id) {
            return Err(Retcode::RetCanNotFindTeam);
        }

        if avatar_guid_vec.len() > 4 {
            return Err(Retcode::RetFail);
        }

        let mut avatar_guid_set = HashSet::with_capacity(avatar_guid_vec.len());
        for guid in avatar_guid_vec {
            if !avatar_guid_set.insert(*guid) {
                tracing::info!("duplicate avatar guid:{guid}");
                return Err(Retcode::RetDuplicateAvatar);
            }
        }

        for guid in avatar_guid_vec {
            if self.find_avatar(*guid).is_none() {
                return Err(Retcode::RetCanNotFindAvatar);
            }
        }

        Ok(())
    }

    pub fn check_change_cur_avatar(&self, _guid: u64) -> Result<(), Retcode> {
        Ok(())
    }

    pub fn on_login(&mut self, _is_new_player: bool) {
        for index in 1..=4 {
            if !self.avatar_team_map.contains_key(&index) {
                self.avatar_team_map.insert(
                    index,
                    RefCell::new(AvatarTeam {
                        avatar_vec: Vec::new(),
                        last_cur_avatar_guid: 0,
                        team_name: String::new(),
                    }),
                );
            }
        }

        self.owned_flycloak_set.insert(140001);
        self.try_add_default_unlock_costume();
    }

    pub fn notify_all_data(&self) {
        let notify = AvatarDataNotify {
            avatar_list: self
                .avatar_map
                .iter()
                .map(|(_, av)| av.borrow().to_client())
                .collect(),
            cur_avatar_team_id: self.cur_avatar_team_id,
            avatar_team_map: self
                .avatar_team_map
                .iter()
                .map(|(id, team)| {
                    (
                        *id,
                        proto::AvatarTeam {
                            team_name: team.borrow().team_name.clone(),
                            avatar_guid_list: team.borrow().avatar_vec.clone(),
                        },
                    )
                })
                .collect(),
            choose_avatar_guid: self.choose_avatar_guid,
            owned_flycloak_list: self.owned_flycloak_set.clone().into_iter().collect(),
            owned_costume_list: self.owned_costume_set.clone().into_iter().collect(),
            ..Default::default()
        };

        self.player().unwrap().send_proto(notify);
    }

    fn try_add_default_unlock_costume(&mut self) {
        // TODO! this is for free skins.
    }

    pub fn on_first_login(&self) {
        // empty.
    }

    pub fn set_born_avatar(&mut self, avatar_id: u32) -> Result<(), Retcode> {
        if self.get_avatar_count() != 0 {
            tracing::error!("can not redo it");
            return Err(Retcode::RetFail);
        }

        if avatar_id != Self::TRAVELER_MALE_ID && avatar_id != Self::TRAVELER_FEMALE_ID {
            tracing::error!("invalid born avatar, avatar_id:{avatar_id}");
            return Err(Retcode::RetFail);
        }

        self.cur_avatar_team_id = 1;
        let Some(guid) = self.add_formal_avatar(avatar_id, false, 1, 0) else {
            tracing::error!("add_formal_avatar fails, avatar_id:{avatar_id}");
            return Err(Retcode::RetFail);
        };

        let mut team = self.avatar_team_map.get_mut(&1).unwrap().borrow_mut();
        team.avatar_vec.push(guid);
        team.last_cur_avatar_guid = guid;
        self.choose_avatar_guid = guid;
        self.last_background_avatar_recover_time = time_utils::get_now() as u32;
        self.spring_auto_use_percent = 50;
        self.cur_avatar_team_id = 1;

        Ok(())
    }

    pub fn add_formal_avatar(
        &mut self,
        avatar_id: u32,
        is_notify: bool,
        add_avatar_reason: u32,
        action_reason: u32,
    ) -> Option<u64> {
        let player = self.player().unwrap();
        if self.has_avatar(avatar_id, 1) {
            tracing::warn!("formal avatar avatar_id:{avatar_id} already exist");
            return None;
        }

        let Some(avatar_config) = iter_avatar_data().find(|a| a.id == avatar_id) else {
            tracing::error!("find_avatar_config fails, avatar_id:{avatar_id}");
            return None;
        };

        let Some(mut avatar) = self.create_avatar(1, avatar_id, 0) else {
            tracing::error!("create_avatar fails, avatar_id:{avatar_id}");
            return None;
        };

        let guid = avatar.base_avatar().guid;

        avatar.base_avatar_mut().set_player(player.clone());
        avatar.base_avatar_mut().skill_depot_id = avatar_config.skill_depot_id;
        avatar.set_level(1);
        avatar.base_avatar_mut().life_state = LifeState::LifeAlive;
        let add_equip_result = player
            .player_item_comp
            .borrow_mut()
            .force_add_equip_by_add_avatar(avatar_config.initial_weapon);

        avatar
            .base_avatar_mut()
            .equip_comp
            .set_init_weapon(add_equip_result.guid);

        avatar.set_cur_hp_full();
        if self
            .add_avatar(avatar, is_notify, add_avatar_reason, action_reason)
            .is_err()
        {
            tracing::error!("add_avatar failed, avatar_id:{avatar_id}");
            return None;
        }

        Some(guid)
    }

    pub fn add_avatar(
        &mut self,
        mut avatar: Avatar,
        is_notify: bool,
        _add_avatar_reason: u32,
        _action_reason: u32,
    ) -> Result<(), Retcode> {
        avatar.init();
        self.emplace_avatar(avatar)?;

        if is_notify {
            // TODO!
        }

        Ok(())
    }

    fn create_avatar(&self, avatar_type: u32, avatar_id: u32, avatar_guid: u64) -> Option<Avatar> {
        let mut avatar = match avatar_type {
            1 => Avatar::Formal(FormalAvatar::default()),
            2 => Avatar::Trial(TrialAvatar::default()),
            3 => Avatar::Mirror(MirrorAvatar::default()),
            _ => {
                tracing::error!("unknown avatar_type:{avatar_type}");
                return None;
            }
        };

        avatar.base_avatar_mut().avatar_id = avatar_id;

        let avatar_guid = match avatar_guid {
            0 => {
                let player = self.player().unwrap();
                let mut basic_comp = player.player_basic_comp.borrow_mut();
                basic_comp.gen_guid()
            }
            guid => guid,
        };

        if avatar_guid == 0 {
            tracing::error!(
                "gen_guid failed, avatar_type:{avatar_type} avatar_id:{avatar_id} uid:{}",
                self.player().unwrap().uid
            );
            return None;
        }

        avatar.base_avatar_mut().guid = avatar_guid;
        avatar.base_avatar_mut().born_time = time_utils::get_now() as u32;

        Some(avatar)
    }

    pub fn has_avatar(&self, avatar_id: u32, avatar_type: u32) -> bool {
        self.avatar_map.iter().any(|(_, a)| {
            let a = a.borrow();
            a.base_avatar().avatar_id == avatar_id && a.get_avatar_type() == avatar_type
        })
    }

    pub fn find_avatar(&self, guid: u64) -> Option<Rc<RefCell<Avatar>>> {
        self.avatar_map.get(&guid).cloned()
    }

    pub fn find_formal_avatar(&self, guid: u64) -> Option<Rc<RefCell<Avatar>>> {
        let avatar = self.avatar_map.get(&guid).cloned();
        if let Some(avatar) = avatar.as_ref() {
            if avatar.borrow().get_avatar_type() != 1 {
                return None;
            }
        }

        avatar
    }

    pub fn get_cur_avatar(&self) -> Option<Rc<RefCell<Avatar>>> {
        self.cur_avatar_ptr.borrow().upgrade()
    }

    pub fn set_cur_avatar(&mut self, cur_avatar_ptr: &Rc<RefCell<Avatar>>) {
        *self.cur_avatar_ptr.borrow_mut() = Rc::downgrade(cur_avatar_ptr);
    }

    pub fn from_bin(bin: PlayerAvatarCompBin) -> Self {
        let mut comp = Self {
            player: OnceCell::new(),
            avatar_map: BTreeMap::new(),
            trial_avatar_guid_set: HashSet::new(),
            temp_avatar_guid_set: bin.temp_avatar_guid_list.into_iter().collect(),
            avatar_team_map: bin
                .team_map
                .into_iter()
                .map(|(i, t)| {
                    (
                        i,
                        RefCell::new(AvatarTeam {
                            team_name: t.team_name,
                            last_cur_avatar_guid: t.last_cur_avatar_guid,
                            avatar_vec: t.avatar_guid_list,
                        }),
                    )
                })
                .collect(),
            cur_avatar_team_id: bin.cur_team_id,
            last_change_avatar_time_ms: bin.last_change_avatar_time,
            is_spring_auto_use: bin.is_spring_auto_use,
            spring_auto_use_percent: bin.spring_auto_use_percent,
            last_background_avatar_recover_time: bin.last_backgroud_avatar_recover_time,
            is_flyable: bin.is_flyable,
            is_transferable: bin.is_transferable,
            last_avatar_guid: bin.last_avatar_guid,
            choose_avatar_guid: bin.choose_avatar_guid,
            die_type: bin.die_type,
            owned_flycloak_set: bin.owned_flycloak_list.into_iter().collect(),
            owned_costume_set: bin.owned_costume_id_list.into_iter().collect(),
            team_entity: Weak::new(),
            cur_avatar_ptr: RefCell::new(Weak::new()),
        };

        bin.avatar_list.into_iter().for_each(|a| {
            let _ = comp.emplace_avatar(Avatar::from_bin(a));
        });

        comp
    }

    pub fn to_bin(&self) -> PlayerAvatarCompBin {
        PlayerAvatarCompBin {
            avatar_list: self
                .avatar_map
                .values()
                .map(|a| a.borrow().to_bin())
                .collect(),
            team_map: self
                .avatar_team_map
                .iter()
                .map(|(i, t)| {
                    (
                        *i,
                        AvatarTeamBin {
                            team_name: t.borrow().team_name.clone(),
                            last_cur_avatar_guid: t.borrow().last_cur_avatar_guid,
                            avatar_guid_list: t.borrow().avatar_vec.clone(),
                        },
                    )
                })
                .collect(),
            cur_team_id: self.cur_avatar_team_id,
            last_change_avatar_time: self.last_change_avatar_time_ms,
            is_spring_auto_use: self.is_spring_auto_use,
            spring_auto_use_percent: self.spring_auto_use_percent,
            last_backgroud_avatar_recover_time: self.last_background_avatar_recover_time,
            is_flyable: self.is_flyable,
            is_transferable: self.is_transferable,
            last_avatar_guid: self.last_avatar_guid,
            choose_avatar_guid: self.choose_avatar_guid,
            die_type: self.die_type,
            owned_flycloak_list: self.owned_flycloak_set.iter().cloned().collect(),
            owned_costume_id_list: self.owned_costume_set.iter().cloned().collect(),
            temp_avatar_guid_list: self.temp_avatar_guid_set.iter().cloned().collect(),
            ..Default::default()
        }
    }

    pub fn emplace_avatar(&mut self, avatar: Avatar) -> Result<(), Retcode> {
        let guid = avatar.base_avatar().guid;
        if guid == 0 {
            tracing::error!("avatar guid is 0, uid:{}", self.player().unwrap().uid);
            return Err(Retcode::RetFail);
        }

        if !self.avatar_map.contains_key(&guid) {
            if avatar.get_avatar_type() == 2 {
                self.trial_avatar_guid_set.insert(guid);
            }

            self.avatar_map.insert(guid, Rc::new(RefCell::new(avatar)));
            Ok(())
        } else {
            tracing::error!("emplace Avatar failed, uid:{}", self.player().unwrap().uid);
            Err(Retcode::RetFail)
        }
    }

    pub fn get_avatar_count(&self) -> usize {
        self.avatar_map.len()
    }
}
