use std::{
    collections::{BTreeMap, BTreeSet},
    rc::{Rc, Weak},
};

use proto::PlayerItemCompBin;
use tokio::sync::OnceCell;

use crate::player::Player;

use super::{item_store::ItemStore, AddItemResult, Equip, Item, ItemParam, Weapon};

#[derive(Default)]
pub struct PlayerItemComp {
    player: OnceCell<Weak<Player>>,
    pub pack_store: ItemStore,
    pub history_item_set: BTreeSet<u32>,
    pub hcoin: u32,
    pub scoin: u32,
    pub item_cd_map: BTreeMap<u32, u64>,
}

impl PlayerItemComp {
    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) {
        // TODO: check item hard limits
    }

    pub fn on_login(&mut self, _is_new_player: bool) {
        // TODO: Resin changing, ::checkAllMaterialsDelete (?)
    }

    pub fn notify_all_data(&self) {
        self.pack_store.notify_all_data(&self.player().unwrap());
    }

    pub fn force_add_equip_by_add_avatar(&mut self, item_id: u32) -> AddItemResult {
        let item = self.create_item(ItemParam {
            item_id,
            count: 1,
            level: 1,
            promote_level: 0,
        });

        self.pack_store.force_add_equip_by_add_avatar(item)
    }

    pub fn create_item(&mut self, item_param: ItemParam) -> Item {
        self.create_item_batch(vec![item_param]).remove(0)
    }

    pub fn create_item_batch(&mut self, item_param_vec: Vec<ItemParam>) -> Vec<Item> {
        let mut created_items = Vec::with_capacity(item_param_vec.len());
        for param in item_param_vec {
            let guid = self
                .player()
                .unwrap()
                .player_basic_comp
                .borrow_mut()
                .gen_guid();
            // TODO: currently only weapons are supported!

            created_items.push(Item::Weapon(Weapon {
                base: Equip {
                    is_locked: false,
                    base: super::BaseItem {
                        item_id: param.item_id,
                        guid,
                    },
                },
                level: param.level,
                promote_level: param.promote_level,
                ..Default::default()
            }));
        }

        created_items
    }

    pub fn from_bin(bin: PlayerItemCompBin) -> Self {
        Self {
            player: OnceCell::new(),
            pack_store: ItemStore::from_bin(bin.pack_store.unwrap_or_default()),
            history_item_set: bin.history_item_list.into_iter().collect(),
            hcoin: bin.hcoin,
            scoin: bin.scoin,
            item_cd_map: bin.item_cd_map.into_iter().collect(),
        }
    }

    pub fn to_bin(&self) -> PlayerItemCompBin {
        PlayerItemCompBin {
            pack_store: Some(self.pack_store.to_bin()),
            history_item_list: self.history_item_set.clone().into_iter().collect(),
            hcoin: self.hcoin,
            scoin: self.scoin,
            item_cd_map: self.item_cd_map.clone().into_iter().collect(),
            ..Default::default()
        }
    }
}
