use std::{cell::RefCell, collections::BTreeMap, rc::Rc, sync::LazyLock};

use common::tools::string_utils::get_string_hash;
use proto::{AbilityControlBlock, AbilityEmbryo};

use crate::player::avatar::Avatar;

// TODO: Real ability logic
#[derive(Default)]
pub struct AbilityComp {
    pub creature: Option<Rc<RefCell<Avatar>>>,
    target_ability_id_map: BTreeMap<u32, (u32, u32)>,
    last_ability_id: u32,
}

const COMMON_AVATAR_ABILITIES: [&'static str; 9] = [
    "Avatar_DefaultAbility_VisionReplaceDieInvincible",
    "Avatar_DefaultAbility_AvartarInShaderChange",
    "Avatar_SprintBS_Invincible",
    "Avatar_Freeze_Duration_Reducer",
    "Avatar_Attack_ReviveEnergy",
    "Avatar_Component_Initializer",
    "Avatar_HDMesh_Controller",
    "Avatar_Trampoline_Jump_Controller",
    "Avatar_ArkheGrade_CD_Controller",
];

impl AbilityComp {
    pub fn init(&mut self, creature: Rc<RefCell<Avatar>>) {
        self.creature = Some(creature);
        self.init_target_ability();
    }

    pub fn init_target_ability(&mut self) {
        let mut target_ability_vec = Vec::new();

        for ability_name in &COMMON_AVATAR_ABILITIES {
            target_ability_vec.push((get_string_hash(ability_name), 0));
        }

        self.get_all_static_config_abilities(&mut target_ability_vec);

        for (ability_name_hash, override_name_hash) in target_ability_vec {
            self.add_target_ability(ability_name_hash, override_name_hash);
        }
    }

    fn add_target_ability(&mut self, ability_name_hash: u32, mut override_name_hash: u32) {
        static DEFAULT_OVERRIDE_NAME_HASH: LazyLock<u32> =
            LazyLock::new(|| get_string_hash("Default"));

        if override_name_hash == 0 {
            override_name_hash = *DEFAULT_OVERRIDE_NAME_HASH;
        }

        let ability_id = self.last_ability_id + 1;
        self.last_ability_id += 1;

        self.target_ability_id_map
            .insert(ability_id, (ability_name_hash, override_name_hash));
    }

    pub fn get_proto_ability_control_block(
        &self,
        proto_ability_control_block: &mut AbilityControlBlock,
    ) {
        for (id, (name_hash, override_name_hash)) in self.target_ability_id_map.iter() {
            proto_ability_control_block
                .ability_embryo_list
                .push(AbilityEmbryo {
                    ability_id: *id,
                    ability_name_hash: *name_hash,
                    ability_override_name_hash: *override_name_hash,
                });
        }
    }

    fn get_all_static_config_abilities(&self, target_ability_vec: &mut Vec<(u32, u32)>) {
        let avatar_id = self
            .creature
            .as_ref()
            .unwrap()
            .borrow()
            .base_avatar()
            .avatar_id;

        let avatar_data = data::iter_avatar_data()
            .find(|a| a.id == avatar_id)
            .unwrap();

        let name = avatar_data.icon_name.replace("UI_AvatarIcon_", ""); // TODO: that's kind of hack
        let Some(config) = data::get_config_avatar(&name) else {
            tracing::error!("get_config_avatar failed, name:{name}");
            return;
        };

        for ability_entry in config.abilities.iter() {
            target_ability_vec.push((
                get_string_hash(&ability_entry.ability_name),
                get_string_hash(&ability_entry.ability_override),
            ));
        }
    }
}
