use proto::{ItemBin, ItemParamBin};

use super::Weapon;

pub enum Item {
    Weapon(Weapon),
}

impl Item {
    pub fn item_id(&self) -> u32 {
        self.base().item_id
    }

    pub fn guid(&self) -> u64 {
        self.base().guid
    }

    pub fn base(&self) -> &BaseItem {
        match self {
            Item::Weapon(weapon) => &weapon.base.base,
        }
    }

    pub fn to_client(&self) -> proto::Item {
        match self {
            Self::Weapon(weapon) => weapon.to_client(),
        }
    }

    pub fn from_bin(bin: ItemBin) -> Self {
        match bin.item_type {
            4 => {
                // ugly but saving system is retarded.. (oneof-based polymorphism)
                let proto::item_bin::Detail::Equip(equip) = bin.detail.clone().unwrap() else {
                    panic!("Failed to unwrap EquipBin for Weapon")
                };
                let proto::equip_bin::Detail::Weapon(weapon) = equip.detail.clone().unwrap() else {
                    panic!("Failed to unwrap WeaponBin")
                };

                Item::Weapon(Weapon::from_bin(bin, equip, weapon))
            }
            _ => todo!("item type {}", bin.item_type),
        }
    }

    pub fn to_bin(&self) -> ItemBin {
        match self {
            Item::Weapon(weapon) => weapon.to_bin(),
        }
    }
}

#[allow(dead_code)]
pub struct AddItemResult {
    pub item_id: u32,
    pub guid: u64,
    pub add_count: u32,
    pub cur_count: u32,
}

pub struct ItemParam {
    pub item_id: u32,
    pub count: u32,
    pub level: u32,
    pub promote_level: u32,
}

impl ItemParam {
    pub fn from_bin(bin: ItemParamBin) -> Self {
        Self {
            item_id: bin.item_id,
            count: bin.count,
            level: bin.level,
            promote_level: bin.promote_level,
        }
    }

    pub fn to_bin(&self) -> ItemParamBin {
        ItemParamBin {
            item_id: self.item_id,
            count: self.count,
            level: self.level,
            promote_level: self.promote_level,
        }
    }
}

#[derive(Default)]
pub struct BaseItem {
    pub item_id: u32,
    pub guid: u64,
}

impl BaseItem {
    pub fn to_client(&self, detail: proto::item::Detail) -> proto::Item {
        proto::Item {
            item_id: self.item_id,
            guid: self.guid,
            detail: Some(detail),
        }
    }

    pub fn from_bin(bin: ItemBin) -> Self {
        Self {
            item_id: bin.item_id,
            guid: bin.guid,
        }
    }

    pub fn to_bin(&self, item_type: u32) -> ItemBin {
        ItemBin {
            item_id: self.item_id,
            guid: self.guid,
            item_type,
            ..Default::default()
        }
    }
}
