using Campofinale.Resource;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Bson;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MongoDB.Bson.Serialization.IdGenerators;
using static Campofinale.Resource.ResourceManager;
using Google.Protobuf.Collections;
using Campofinale.Packets.Sc;
using Campofinale.Protocol;
using CsvHelper.Configuration.Attributes;

namespace Campofinale.Game.Inventory
{
    public class Item
    {
        [BsonId(IdGenerator = typeof(ObjectIdGenerator))]
        public ObjectId _id { get; set; }
        [BsonElement("templateId")]
        public string id;
        public ulong guid;
        public int amount = 1;
        public ulong owner;
        public ulong level = 1;
        public ulong xp;
        public bool locked = false;
        public ulong attachGemId;
        public ulong breakthroughLv;
        public ulong refineLv;
        public Item() { 
        
        }
        public Item(ulong owner, string id, int amt)
        {
            this.owner = owner;
            this.id = id;
            this.amount = amt;
            this.level = GetDefaultLevel();
            guid = GetOwner().random.Next();
        }
        public Item(ulong owner, string id, ulong level)
        {
            this.owner = owner;
            this.id = id;
            this.amount = 1;
            this.level = level;
            guid = GetOwner().random.Next();
        }
        public ItemStorageSpace StorageSpace()
        {
            return ResourceManager.itemTypeTable[GetItemTable().type].storageSpace;
        }
        public ulong GetDefaultLevel()
        {
            switch (ItemType)
            {
                case ItemValuableDepotType.Weapon:
                    return 1;
                case ItemValuableDepotType.Equip:
                    return equipTable[id].minWearLv;
                default:
                    return 0;
            }
        }
        public List<AttributeModifier> GetEquipAttributeModifier()
        {
            List<AttributeModifier> modifiers = ResourceManager.equipTable[id].attrModifiers;

            return modifiers;
        }
        public ItemValuableDepotType ItemType
        {
            get
            {
                return ResourceManager.GetItemTable(id).valuableTabType;
            }
        }
        public ItemTable GetItemTable()
        {
            return ResourceManager.GetItemTable(id);
        }
        public virtual ScdItemGrid ToProto()
        {
            try
            {
                switch (ItemType)
                {
                    case ItemValuableDepotType.WeaponGem:
                        return new ScdItemGrid()
                        {
                            Count = 1,
                            Id = id,

                            Inst = new()
                            {
                                InstId = guid,
                                Gem = new()
                                {
                                    GemId = guid,
                                    TemplateId= ResourceManager.GetItemTemplateId(id),
                                    WeaponId= GetOwner().inventoryManager.items.Find(i=>i.attachGemId==guid)!=null ? GetOwner().inventoryManager.items.Find(i => i.attachGemId == guid).guid: 0,
                                    
                                },
                                IsLock = locked
                            }
                        };
                    case ItemValuableDepotType.Weapon:
                        return new ScdItemGrid()
                        {
                            Count = 1,
                            Id = id,

                            Inst = new()
                            {
                                InstId = guid,
                                Weapon = new()
                                {
                                    InstId = guid,
                                    EquipCharId = GetOwner().chars.Find(c => c.weaponGuid == guid) != null ? GetOwner().chars.Find(c => c.weaponGuid == guid).guid : 0,
                                    WeaponLv = level,
                                    TemplateId = ResourceManager.GetItemTemplateId(id),
                                    Exp = xp,
                                    AttachGemId = attachGemId,
                                    
                                    BreakthroughLv = breakthroughLv,
                                    RefineLv = refineLv
                                },
                                
                                IsLock = locked
                            }
                        };
                    case ItemValuableDepotType.Equip:
                        ScdItemGrid equip=new ScdItemGrid()
                        {
                            Count = 1,
                            Id = id,

                            Inst = new()
                            {
                                InstId = guid,

                                Equip = new()
                                {

                                    EquipCharId = GetOwner().chars.Find(c => c.IsEquipped(guid)) != null ? GetOwner().chars.Find(c => c.IsEquipped(guid)).guid : 0,
                                    Equipid = guid,
                                    Templateid = ResourceManager.GetItemTemplateId(id),
                                    
                                },
                                IsLock = locked
                            }
                        };
                        foreach (var item in GetEquipAttributeModifier())
                        {
                            equip.Inst.Equip.Attrs.Add(new EquipAttr()
                            {
                                AttrType= (int)item.attrType,
                                ModifierType=(int)item.modifierType,
                                ModifierValue=item.attrValue,
                                ModifyAttributeType=item.modifyAttributeType,
                            });
                        }
                        return equip;
                    default:
                        return new ScdItemGrid()
                        {
                            Count = amount,
                            Id = id,
                        };
                }
            }
            catch(Exception e)
            {
                return new ScdItemGrid()
                {
                    Count = amount,
                    Id = id,
                };
            }
            
        }
        public Player GetOwner()
        {
            return Server.clients.Find(c => c.roleId == this.owner);
        }
        public (ulong, ulong, ulong) CalculateLevelAndGoldCost(ulong addedXp)
        {
            ulong gold = 0;
            ulong curLevel = this.level;
            WeaponBasicTable table = ResourceManager.weaponBasicTable[id];
            WeaponUpgradeTemplateTable upgradeTable = ResourceManager.weaponUpgradeTemplateTable[table.levelTemplateId];
            while (addedXp >= upgradeTable.list.Find(c=>c.weaponLv==curLevel).lvUpExp)
            {
                gold += upgradeTable.list.Find(c => c.weaponLv == curLevel).lvUpGold;
                addedXp -= upgradeTable.list.Find(c => c.weaponLv == curLevel).lvUpExp;
                curLevel++;
                if (curLevel >= 80)
                {
                    curLevel = 80;
                }
            }
            return (curLevel, gold, addedXp);
        }
        public ulong GetMaterialExp(string id)
        {
            switch (id)
            {
                case "item_weapon_expcard_low":
                    return 200;
                case "item_weapon_expcard_mid":
                    return 1000;
                case "item_weapon_expcard_high":
                    return 10000;
                default:
                    return 0;
            }
        }
        public void LevelUp(MapField<string, ulong> costItemId2Count, RepeatedField<ulong> costWeaponIds)
        {
            //TODO add exp from costWeapons
            ulong addedXp = 0;
            foreach (var material in costItemId2Count)
            {
                addedXp += GetMaterialExp(material.Key) * material.Value;
            }
            (ulong, ulong, ulong) CalculatedValues = CalculateLevelAndGoldCost(xp + addedXp);

            costItemId2Count.Add("item_gold",CalculatedValues.Item2);
            if (GetOwner().inventoryManager.ConsumeItems(costItemId2Count))
            {
                this.level = CalculatedValues.Item1;
                this.xp = CalculatedValues.Item3;
                ScWeaponAddExp levelUp = new()
                {
                    Weaponid = guid,
                    WeaponLv=level,
                    NewExp=xp,

                };
                GetOwner().Send(ScMsgId.ScWeaponAddExp, levelUp);
                GetOwner().Send(new PacketScSyncWallet(GetOwner()));
            }
        }
        public bool InstanceType()
        {
            switch (ItemType)
            {
                case ItemValuableDepotType.Weapon:
                    return true;
                case ItemValuableDepotType.WeaponGem:
                    return true;
                case ItemValuableDepotType.Equip:
                    return true;
                case ItemValuableDepotType.SpecialItem:
                    return false;
                case ItemValuableDepotType.MissionItem:
                    return true;
                default:
                    return false;
            }
        }


    }

}
