use std::{
    cell::RefCell,
    collections::{BTreeMap, HashMap},
    rc::{Rc, Weak},
    sync::atomic::{AtomicU32, Ordering},
};

use common::tools::time_utils;
use data::{
    math_def::{Vector2, Vector3},
    SceneType,
};
use proto::{
    EnterType, HostPlayerNotify, ProtEntityType, Retcode, SceneBin, SceneDataNotify,
    SceneEntityAppearNotify, SceneEntityDisappearNotify, SceneEntityInfo, SceneForceUnlockNotify,
    ScenePlayerLocationBin, VisionType,
};
use tokio::sync::OnceCell;

use crate::{
    entity::{entity_mgr, entity_utils, Entity, VisionContext},
    player::{avatar::Avatar, Player},
};

use super::{
    dungeon_scene::DungeonScene, player_world_scene::PlayerWorldScene, MPLevelEntity, PlayerWorld,
    SceneSightComp,
};

pub enum Scene {
    PlayerWorld(PlayerWorldScene),
    Dungeon(DungeonScene),
}

impl Scene {
    pub fn new(scene_id: u32) -> Self {
        let scene_type = data::iter_scene_data()
            .find(|s| s.id == scene_id)
            .unwrap()
            .r#type;

        match scene_type {
            SceneType::World => Self::PlayerWorld(PlayerWorldScene::new(scene_id)),
            SceneType::Dungeon => Self::Dungeon(DungeonScene::new(scene_id)),
            _ => panic!("Invalid scene type {scene_type:?}"),
        }
    }

    pub fn from_bin(scene_id: u32, bin: SceneBin) -> Self {
        let scene_type = data::iter_scene_data()
            .find(|s| s.id == scene_id)
            .unwrap()
            .r#type;

        match scene_type {
            SceneType::World => Self::PlayerWorld(PlayerWorldScene::from_bin(scene_id, bin)),
            SceneType::Dungeon => Self::Dungeon(DungeonScene::from_bin(scene_id, bin)),
            _ => panic!("Invalid scene type {scene_type:?}"),
        }
    }

    pub fn to_bin(&self) -> SceneBin {
        match self {
            Self::PlayerWorld(scene) => scene.to_bin(),
            Self::Dungeon(scene) => scene.to_bin(),
        }
    }

    pub fn base(&self) -> &BaseScene {
        match self {
            Self::PlayerWorld(scene) => &scene.base,
            Self::Dungeon(scene) => &scene.base,
        }
    }

    pub fn base_mut(&mut self) -> &mut BaseScene {
        match self {
            Self::PlayerWorld(scene) => &mut scene.base,
            Self::Dungeon(scene) => &mut scene.base,
        }
    }

    pub fn gen_new_entity_id(&self, ty: ProtEntityType) -> u32 {
        self.base().gen_new_entity_id(ty)
    }

    pub fn init(&mut self) {
        match self {
            Self::PlayerWorld(scene) => scene.init(),
            Self::Dungeon(scene) => scene.init(),
        }
    }

    pub fn player_enter(
        &mut self,
        player: &Rc<Player>,
        pos: Vector3,
        rot: Vector3,
        is_relogin: bool,
        enter_scene_avatar: Vec<Rc<RefCell<Avatar>>>,
        appear_avatar_ptr: &Rc<RefCell<Avatar>>,
    ) -> Result<(), Retcode> {
        let uid = player.uid;
        let Some(_peer_id) = self.base().get_peer_id(uid) else {
            return Err(Retcode::RetFail);
        };

        self.base_mut()
            .player_map
            .insert(player.uid, Rc::downgrade(player));

        {
            let Some(host_player) = self
                .base()
                .host_player_wtr
                .as_ref()
                .map(|p| p.upgrade())
                .flatten()
            else {
                return Err(Retcode::RetFail);
            };

            let mut host_avatar_comp = host_player.player_avatar_comp.borrow_mut();
            if host_avatar_comp.team_entity.upgrade().is_none() {
                let team_entity =
                    Rc::new(RefCell::new(entity_mgr::create_avatar_team_entity(self)));
                team_entity.borrow_mut().set_player(player);
                host_avatar_comp.team_entity = Rc::downgrade(&team_entity);

                self.base_mut()
                    .add_gridless_entity(team_entity as Rc<RefCell<dyn Entity>>)?;
            }
        }

        let mut avatar_comp = player.player_avatar_comp.borrow_mut();
        if let Some(cur_avatar) = avatar_comp.get_cur_avatar() {
            if cur_avatar.borrow().is_on_scene() {
                tracing::error!("[ENTER] last cur avatar is on scene! uid: {}", player.uid);
            }
        }

        let mut scene_comp = player.player_scene_comp.borrow_mut();
        let dest_enter_type = scene_comp.dest_enter_type;
        let prev_scene_id = scene_comp.cur_scene_id;
        let new_scene_id = self.base().scene_id;

        scene_comp.cur_scene_id = new_scene_id;
        scene_comp.cur_scene_owner_uid = self.base().owner_uid();

        drop(scene_comp);
        // SET after: player.player_scene_comp.lock().cur_scene_wtr = self

        avatar_comp.set_cur_avatar(appear_avatar_ptr);
        drop(avatar_comp);

        let appear_avatar_guid = {
            let appear_avatar = appear_avatar_ptr.borrow();
            appear_avatar.base_avatar().guid
        };

        let avatar_guid_vec = enter_scene_avatar
            .iter()
            .map(|a| a.borrow().base_avatar().guid)
            .collect();
        let cur_world_ptr = self.base().cur_world_wtr.upgrade().unwrap();
        cur_world_ptr
            .borrow_mut()
            .scene_team
            .set_player_avatar_team_and_add_to_scene(
                player.uid,
                avatar_guid_vec,
                appear_avatar_guid,
                self,
                false,
            )
            .map_err(|err| {
                tracing::error!(
                    "set_player_avatar_team_and_add_to_scene failed, uid:{}",
                    player.uid
                );
                err
            })?;

        if self.base().owner_uid() == player.uid {
            let scene_id = self.base().scene_id;

            let mut scene_comp = player.player_scene_comp.borrow_mut();
            scene_comp.my_cur_scene_id = scene_id;
            scene_comp.my_cur_player_scene_id = scene_id;
            // TODO: differentiate between home/player scene!
            // scene_comp.my_home_scene_id = scene_id;
        }

        if prev_scene_id != new_scene_id
            || is_relogin
            || dest_enter_type == EnterType::EnterGotoRecreate
        {
            self.notify_scene_and_host_data(player.uid);
            player.notify_player_enter_scene_info(self);
            // Player::setIsDataResVersionChanged(player, 0);
        } else if prev_scene_id == new_scene_id {
            // TODO: for Goto/Jump ('re-enter' current scene)
            // v91 = Player::getAvatarComp(v90);
            // std::function<ForeachPolicy ()(Avatar &)>::function<Scene::playerEnter(Player &,Vector3 const&,Vector3 const&,bool,std::vector<std::shared_ptr<Avatar>> const&,std::shared_ptr<Avatar>)::{lambda(Avatar &)#1},void,void>(
            //   (std::function<ForeachPolicy(Avatar&)> *const)&v140,
            //  (Scene::playerEnter::<lambda(Avatar&)>)(v7 + 480));
            // PlayerAvatarComp::foreachMyAvatarInSceneTeam(v91, (std::function<ForeachPolicy(Avatar&)> *)&v140);
        }

        let scene_player_location = ScenePlayerLocation {
            cur_pos: pos.clone(),
            cur_rot: rot.clone(),
            last_valid_pos: pos.clone(),
            last_valid_rot: rot.clone(),
        };

        self.set_player_location(player.uid, scene_player_location);

        {
            let avatar_comp = player.player_avatar_comp.borrow();
            let cur_avatar_ptr = avatar_comp.get_cur_avatar().unwrap();
            let mut cur_avatar = cur_avatar_ptr.borrow_mut();
            cur_avatar.set_position(pos.clone());
            cur_avatar.set_rotation(rot.clone());
            cur_avatar.set_last_valid_position(pos);
            cur_avatar.set_last_valid_rotation(rot);
        }

        // TODO: Scene::notifyAllPlayerInfo();
        cur_world_ptr.borrow().scene_team.notify_scene_team_update();

        // Scene::notifyAllTeamEntity() -> SyncTeamEntityNotify ?
        // Scene::notifyAllPlayTeamEntity()

        Ok(())
    }

    pub fn get_or_create_mp_level_entity(&mut self) -> Rc<RefCell<MPLevelEntity>> {
        if let Some(mp_level_entity) = self.base().mp_level_entity_ptr.as_ref() {
            return mp_level_entity.clone();
        }

        let mut mp_level_entity = MPLevelEntity::default();
        mp_level_entity.set_authority_peer_id(self.base().get_host_peer_id().unwrap_or_default());
        mp_level_entity.set_entity_id(self.gen_new_entity_id(ProtEntityType::ProtEntityMpLevel));

        let mp_level_entity_ptr = Rc::new(RefCell::new(mp_level_entity));
        self.add_gridless_entity(mp_level_entity_ptr.clone() as Rc<RefCell<dyn Entity>>)
            .unwrap();

        self.base_mut().mp_level_entity_ptr = Some(mp_level_entity_ptr.clone());
        mp_level_entity_ptr
    }

    pub fn set_player_location(&mut self, uid: u32, player_location: ScenePlayerLocation) {
        if self.base().owner_uid() == uid {
            self.base_mut().owner_player_location = player_location.clone();
        }

        tracing::info!(
            "[ENTER_SCENE] set_player_location, last_valid_pos:{:?}, cur_pos:{:?}",
            player_location.last_valid_pos,
            player_location.cur_pos
        );

        self.base_mut()
            .player_location_map
            .insert(uid, player_location);
    }

    fn notify_scene_and_host_data(&self, uid: u32) {
        let Some(player) = self.base().find_player(uid) else {
            tracing::warn!("find_player failed, uid:{uid}");
            return;
        };

        self.notify_all_unlock_force(player.as_ref());
        self.notify_host_to_player(player.as_ref());
        self.notify_scene_data(player.as_ref());

        if false
        // if let Some(home_comp) = self.base().get_own_home()
        {
            // home_comp.notify_game_time(player.as_ref());
        } else {
            let own_player = self.base().own_player().unwrap();
            own_player
                .player_basic_comp
                .borrow()
                .notify_game_time(player.as_ref());
        }
    }

    fn notify_all_unlock_force(&self, player: &Player) {
        player.send_proto(SceneForceUnlockNotify {
            force_id_list: self.base().unlocked_force_list.clone(),
            is_add: false,
        });
    }

    fn notify_host_to_player(&self, player: &Player) {
        let Some(host_player) = self.base().get_host_player() else {
            tracing::error!("host_player_ptr is None");
            return;
        };

        player.send_proto(HostPlayerNotify {
            host_uid: host_player.uid,
            host_peer_id: self.base().get_peer_id(host_player.uid).unwrap(),
        });
    }

    fn notify_scene_data(&self, player: &Player) {
        let mut scene_data_notify = SceneDataNotify::default();
        if self.fill_scene_data_notify(&mut scene_data_notify).is_err() {
            tracing::warn!("fill_scene_data_notify failed");
            return;
        }

        player.send_proto(scene_data_notify);
    }

    fn fill_scene_data_notify(&self, _notify: &mut SceneDataNotify) -> Result<(), Retcode> {
        // TODO!
        Ok(())
    }

    pub fn add_avatar_and_weapon_entity(
        &mut self,
        avatar_ptr: Rc<RefCell<Avatar>>,
        _is_enter_scene: bool,
    ) -> Result<(), Retcode> {
        {
            let mut avatar = avatar_ptr.borrow_mut();
            avatar.set_entity_id(self.gen_new_entity_id(ProtEntityType::ProtEntityAvatar));

            tracing::info!(
                "[LR] add_avatar_and_weapon_entity, avatar_id:{} avatar_guid:{} entity_id:{}",
                avatar.base_avatar().avatar_id,
                avatar.base_avatar().guid,
                avatar.entity_id()
            );
        }

        self.add_gridless_entity(avatar_ptr.clone() as Rc<RefCell<dyn Entity>>)
            .map_err(|_| {
                tracing::warn!("add_gridless_entity fails");
                Retcode::RetFail
            })?;

        let ability_comp = {
            let avatar = avatar_ptr.borrow();
            avatar.base_avatar().ability_comp.clone()
        };

        ability_comp.borrow_mut().init(avatar_ptr.clone());

        let mut avatar = avatar_ptr.borrow_mut();
        let Some(weapon_gadget) = avatar.base_avatar_mut().equip_comp.weapon_gadget.as_mut() else {
            tracing::error!("missing weapon gadget!");
            return Err(Retcode::RetFail);
        };

        weapon_gadget
            .borrow_mut()
            .set_entity_id(self.gen_new_entity_id(ProtEntityType::ProtEntityWeapon));

        self.add_gridless_entity(weapon_gadget.clone() as Rc<RefCell<dyn Entity>>)
            .map_err(|_| {
                tracing::warn!(
                    "add_gridless_entity fails, weapon_entity_id:{}",
                    weapon_gadget.borrow().entity_id()
                );
                Retcode::RetFail
            })?;

        weapon_gadget.borrow_mut().init_ability().map_err(|_| {
            tracing::warn!("init_ability fails");
            Retcode::RetFail
        })?;

        Ok(())
    }

    pub fn del_avatar_and_weapon_entity(&mut self, avatar_ptr: Rc<RefCell<Avatar>>) {
        let entity_id = avatar_ptr.borrow().entity_id();
        avatar_ptr.borrow_mut().set_entity_id(0);
        if self
            .del_gridless_entity(avatar_ptr.clone() as Rc<RefCell<dyn Entity>>)
            .is_err()
        {
            tracing::warn!(
                "del_gridless_entity_fails {}",
                avatar_ptr.borrow().get_desc()
            );
            return;
        }

        let avatar = avatar_ptr.borrow();
        if let Some(gadget) = avatar.base_avatar().equip_comp.weapon_gadget.clone() {
            if self
                .del_gridless_entity(gadget.clone() as Rc<RefCell<dyn Entity>>)
                .is_err()
            {
                tracing::warn!(
                    "del_gridless_entity fails, weapon_entity_id:{}",
                    gadget.borrow().entity_id()
                );
                return;
            }
        }

        tracing::info!(
            "del_avatar_and_weapon_entity finished, avatar_entity_id:{entity_id}, guid:{}",
            avatar.base_avatar().guid
        );
    }

    pub fn entity_appear(
        &mut self,
        entity: &Rc<RefCell<dyn Entity>>,
        vision_context: VisionContext,
    ) -> Result<(), Retcode> {
        let sight_comp = self.base_mut().sight_comp.as_mut().unwrap();
        let Ok(meet_entity_vec) = sight_comp.place_entity(entity.clone()) else {
            tracing::error!("place_entity fails");
            return Err(Retcode::RetFail);
        };

        let (pos, entity_id) = {
            let entity = entity.borrow();
            (
                Vector2 {
                    x: entity.position().x,
                    y: entity.position().z,
                },
                entity.entity_id(),
            )
        };

        let coordinate =
            sight_comp.pos_to_coordinate(sight_comp.get_vision_level_type(&entity), &pos);

        tracing::info!(
            "[FY] meet entity vec: {:?} @ {:?}",
            meet_entity_vec
                .iter()
                .map(|a| a.borrow().get_desc())
                .collect::<Vec<_>>(),
            coordinate
        );

        self.base_mut().entity_map.insert(entity_id, entity.clone());

        // TODO: PlayerViewMgr

        if vision_context.vision_type != VisionType::VisionReplaceNoNotify {
            for player_wtr in self.base().player_map.values() {
                if let Some(player) = player_wtr.upgrade() {
                    self.notify_entity_appear(&player, &meet_entity_vec, &vision_context)
                }
            }
        }

        Ok(())
    }

    pub fn entity_disappear(
        &mut self,
        entity: &Rc<RefCell<dyn Entity>>,
        vision_context: VisionContext,
    ) -> Result<(), Retcode> {
        if !entity.borrow().is_on_scene() {
            tracing::info!("entity is not on scene {}", entity.borrow().get_desc());
            return Ok(());
        }

        self.base_mut()
            .sight_comp
            .as_mut()
            .unwrap()
            .remove_entity(entity);

        // TODO: disappear nearby entities on avatar death (PROT_ENTITY_AVATAR and not replace)
        if vision_context.vision_type != VisionType::VisionReplaceNoNotify {
            for player_wtr in self.base().player_map.values() {
                if let Some(player) = player_wtr.upgrade() {
                    self.notify_entity_disappear(
                        &player,
                        &[entity.borrow().entity_id()],
                        &vision_context,
                    )
                }
            }
        }

        Ok(())
    }

    fn notify_entity_appear(
        &self,
        player: &Player,
        entity_vec: &[Rc<RefCell<dyn Entity>>],
        context: &VisionContext,
    ) {
        let mut notify = SceneEntityAppearNotify::default();

        for entity_ptr in entity_vec {
            let entity = entity_ptr.borrow();
            let mut scene_entity_info = SceneEntityInfo::default();
            entity.to_client(&mut scene_entity_info);
            notify.entity_list.push(scene_entity_info);
        }

        notify.appear_type = context.vision_type.into();
        notify.param = context.param;

        player.send_proto(notify);
    }

    fn notify_entity_disappear(
        &self,
        player: &Player,
        entity_id_vec: &[u32],
        context: &VisionContext,
    ) {
        player.send_proto(SceneEntityDisappearNotify {
            entity_list: entity_id_vec.to_vec(),
            disappear_type: context.vision_type.into(),
            param: context.param,
        });
    }

    fn add_gridless_entity(&mut self, entity: Rc<RefCell<dyn Entity>>) -> Result<(), Retcode> {
        self.base_mut().add_gridless_entity(entity)
    }

    fn del_gridless_entity(&mut self, entity: Rc<RefCell<dyn Entity>>) -> Result<(), Retcode> {
        self.base_mut().del_gridless_entity(entity)
    }

    pub fn pre_player_login(&mut self, is_relogin: bool) {
        self.base_mut().pre_player_login(is_relogin);
    }

    pub fn set_own_player(&self, player: Rc<Player>) {
        self.base().set_own_player(player);
    }
}

#[derive(Default, Clone)]
pub struct ScenePlayerLocation {
    pub cur_pos: Vector3,
    pub cur_rot: Vector3,
    pub last_valid_pos: Vector3,
    pub last_valid_rot: Vector3,
}

impl ScenePlayerLocation {
    pub fn from_bin(bin: ScenePlayerLocationBin) -> Self {
        Self {
            cur_pos: Vector3::from_bin(bin.cur_pos.unwrap_or_default()),
            cur_rot: Vector3::from_bin(bin.cur_rot.unwrap_or_default()),
            last_valid_pos: Vector3::from_bin(bin.last_valid_pos.unwrap_or_default()),
            last_valid_rot: Vector3::from_bin(bin.last_valid_rot.unwrap_or_default()),
        }
    }

    pub fn to_bin(&self) -> ScenePlayerLocationBin {
        ScenePlayerLocationBin {
            cur_pos: Some(self.cur_pos.to_bin()),
            cur_rot: Some(self.cur_rot.to_bin()),
            last_valid_pos: Some(self.last_valid_pos.to_bin()),
            last_valid_rot: Some(self.last_valid_rot.to_bin()),
        }
    }
}

pub struct ScenePlayerPeerInfo {
    pub uid: u32,
    #[allow(unused)]
    pub enter_time: u64,
}

#[derive(Default)]
pub struct BaseScene {
    own_player: OnceCell<Weak<Player>>,
    pub scene_id: u32,
    pub unlocked_point_list: Vec<u32>,
    pub unlocked_force_list: Vec<u32>,
    pub locked_point_list: Vec<u32>,
    pub owner_player_location: ScenePlayerLocation,
    pub unhide_point_list: Vec<u32>,
    pub scene_transaction: String,
    pub begin_time_ms: u64,
    peer_map: BTreeMap<u32, ScenePlayerPeerInfo>,
    host_player_wtr: Option<Weak<Player>>,
    player_map: HashMap<u32, Weak<Player>>,
    pub cur_world_wtr: Weak<RefCell<PlayerWorld>>,
    pub gridless_entity_map: HashMap<u32, Rc<RefCell<dyn Entity>>>,
    next_entity_index: AtomicU32,
    pub mp_level_entity_ptr: Option<Rc<RefCell<MPLevelEntity>>>,
    pub player_location_map: HashMap<u32, ScenePlayerLocation>,
    pub sight_comp: Option<SceneSightComp>,
    pub entity_map: HashMap<u32, Rc<RefCell<dyn Entity>>>,
}

impl BaseScene {
    pub fn new(scene_id: u32) -> Self {
        Self {
            scene_id,
            ..Default::default()
        }
    }

    pub fn init(&mut self) {
        self.scene_transaction = self.create_scene_transaction_on_init();
        self.begin_time_ms = time_utils::get_now_ms();

        self.sight_comp = Some(
            SceneSightComp::new_grid(
                Vector2::default(),
                Vector2 {
                    // TODO!
                    x: 100000.0,
                    y: 100000.0,
                },
            )
            .unwrap(),
        );
    }

    pub fn pre_player_login(&mut self, _is_relogin: bool) {
        // TODO: BlockGroupComp::prePlayerLogin()
    }

    pub fn player_pre_enter(&mut self, player: Rc<Player>) -> Result<(), Retcode> {
        if self.get_peer_id(player.uid).is_some() {
            tracing::info!("peer_id exist in scene, scene_id:{}", self.scene_id);
            return Ok(());
        }

        if self.peer_map.len() > 3 {
            tracing::info!("scene is full, scene_id:{}", self.scene_id);
            Err(Retcode::RetMpSceneIsFull)
        } else {
            let mut peer_id = 1;
            self.peer_map.keys().for_each(|id| {
                if peer_id == *id {
                    peer_id += 1;
                }
            });

            if peer_id > 7 {
                tracing::error!("invalid peer_id:{peer_id}");
                return Err(Retcode::RetFail);
            }

            player.peer_id.set(peer_id);
            self.peer_map.insert(
                peer_id,
                ScenePlayerPeerInfo {
                    uid: player.uid,
                    enter_time: time_utils::get_now(),
                },
            );

            if self.host_player_wtr.is_none() {
                self.set_host_player(player.clone());
            }

            tracing::info!(
                "[EnterScene] player preEnter scene, scene_id:{}",
                self.scene_id
            );
            Ok(())
        }
    }

    pub fn set_host_player(&mut self, player: Rc<Player>) {
        self.host_player_wtr = Some(Rc::downgrade(&player));

        player.send_proto(HostPlayerNotify {
            host_uid: player.uid,
            host_peer_id: self.get_peer_id(player.uid).unwrap(),
        })
    }

    pub fn get_peer_id(&self, uid: u32) -> Option<u32> {
        self.peer_map
            .iter()
            .find(|(_, info)| info.uid == uid)
            .map(|(id, _)| *id)
    }

    pub fn get_host_peer_id(&self) -> Option<u32> {
        self.host_player_wtr
            .clone()
            .map(|w| w.upgrade())?
            .map(|p| self.get_peer_id(p.uid))?
    }

    pub fn get_host_player(&self) -> Option<Rc<Player>> {
        self.host_player_wtr.clone().map(|w| w.upgrade()).flatten()
    }

    pub fn find_player(&self, uid: u32) -> Option<Rc<Player>> {
        self.player_map.get(&uid).map(|p| p.upgrade()).flatten()
    }

    pub fn add_gridless_entity(
        &mut self,
        entity_ptr: Rc<RefCell<dyn Entity>>,
    ) -> Result<(), Retcode> {
        let entity_id = entity_ptr.borrow().entity_id();
        tracing::info!("[LR] add_gridless_entity, entity_id:{entity_id}");
        if self.gridless_entity_map.contains_key(&entity_id) {
            tracing::warn!("duplicated gridless entity_id:{entity_id}");
            return Err(Retcode::RetFail);
        }

        self.gridless_entity_map
            .insert(entity_id, entity_ptr.clone());

        Ok(())
    }

    pub fn del_gridless_entity(
        &mut self,
        entity_ptr: Rc<RefCell<dyn Entity>>,
    ) -> Result<(), Retcode> {
        let entity_id = entity_ptr.borrow().entity_id();
        self.gridless_entity_map.remove(&entity_id);
        tracing::info!("[LR] del_gridless_entity, entity_id:{entity_id}");

        Ok(())
    }

    pub fn set_player_last_valid_location_on_first_login(&mut self) {
        // Currently hardcoded spawn pos, because no lua.

        self.owner_player_location.last_valid_pos = Vector3 {
            x: 2747.562,
            y: 194.633,
            z: -1719.386,
        };

        self.owner_player_location.last_valid_rot = Vector3 {
            x: 0.0,
            y: 307.0,
            z: 0.0,
        };
    }

    pub fn get_last_owner_location(&self) -> (Vector3, Vector3) {
        (
            self.owner_player_location.last_valid_pos.clone(),
            self.owner_player_location.last_valid_rot.clone(),
        )
    }

    pub fn gen_new_entity_id(&self, ty: ProtEntityType) -> u32 {
        let mut next_entity_index = self.next_entity_index.load(Ordering::SeqCst);
        let mut is_rewind = false;
        if next_entity_index <= 0xFFFFFE {
            next_entity_index = self.next_entity_index.fetch_add(1, Ordering::SeqCst) + 1;
        } else {
            is_rewind = true;
            next_entity_index = 1;
            self.next_entity_index.store(1, Ordering::SeqCst);
        }

        if is_rewind {
            tracing::warn!(
                "next_entity_index rewind. scene_id:{} owner_uid:{} scene_time_ms:{}",
                self.scene_id,
                self.owner_uid(),
                self.get_scene_time_ms()
            );

            // TODO: config->kick_out_on_entity_id_circle
        }

        entity_utils::get_entity_id(ty, next_entity_index)
    }

    pub fn get_scene_time_ms(&self) -> u64 {
        time_utils::get_now_ms() - self.begin_time_ms
    }

    fn create_scene_transaction_on_init(&self) -> String {
        static TRANSACTION_COUNTER: AtomicU32 = AtomicU32::new(0);

        format!(
            "{}-{}-{}-{}",
            self.scene_id,
            self.owner_uid(),
            time_utils::get_now(),
            TRANSACTION_COUNTER.fetch_add(1, Ordering::SeqCst) + 1
        )
    }

    pub fn from_bin(scene_id: u32, bin: SceneBin) -> Self {
        Self {
            scene_id,
            scene_transaction: String::new(),
            begin_time_ms: 0,
            own_player: OnceCell::new(),
            unlocked_point_list: bin.unlocked_point_list,
            unlocked_force_list: bin.unlocked_force_list,
            locked_point_list: bin.locked_point_list,
            owner_player_location: ScenePlayerLocation::from_bin(
                bin.owner_player_location.unwrap_or_default(),
            ),
            unhide_point_list: bin.unhide_point_list,
            peer_map: BTreeMap::new(),
            host_player_wtr: None,
            player_map: HashMap::new(),
            cur_world_wtr: Weak::new(),
            gridless_entity_map: HashMap::new(),
            next_entity_index: AtomicU32::new(0),
            mp_level_entity_ptr: None,
            player_location_map: HashMap::new(),
            sight_comp: None,
            entity_map: HashMap::new(),
        }
    }

    pub fn to_bin(&self) -> SceneBin {
        SceneBin {
            unlocked_point_list: self.unlocked_point_list.clone(),
            unlocked_force_list: self.unlocked_force_list.clone(),
            locked_point_list: self.locked_point_list.clone(),
            owner_player_location: Some(self.owner_player_location.to_bin()),
            unhide_point_list: self.unhide_point_list.clone(),
            ..Default::default()
        }
    }

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

    pub fn set_own_player(&self, player: Rc<Player>) {
        let _ = self.own_player.set(Rc::downgrade(&player));
    }

    pub fn owner_uid(&self) -> u32 {
        self.own_player().unwrap().uid
    }
}
