using System.Collections.Generic;
using System.Linq;
using Fantasy;
using Fantasy.Async;
using NBF.Utils;
using Newtonsoft.Json;

namespace NBF
{
    public class RoleModel
    {
        private static RoleModel _instance;

        public static RoleModel Instance
        {
            get
            {
                _instance ??= new RoleModel();

                return _instance;
            }
        }

        #region 玩家基本信息

        public long Id;
        public string RoomCode { get; set; }
        public RoleInfo Info { get; set; }


        public async FTask GetRoleInfo()
        {
            var response = (Game2C_GetRoleInfoResponse)await Net.Call(new C2Game_GetRoleInfoRequest());
            RoomCode = response.RoomCode;
            Info = response.RoleInfo;
        }

        #endregion

        #region 背包

        public readonly List<ItemInfo> Items = new List<ItemInfo>();
        public readonly List<ItemBindInfo> Rigs = new List<ItemBindInfo>();
        public readonly HashSet<long> BindId = new HashSet<long>();
        public readonly List<long> Slots = new List<long>();

        public async FTask GetBagInfo()
        {
            Items.Clear();
            Rigs.Clear();
            Slots.Clear();
            var response = (Game2C_GetItemsResponse)await Net.Call(new C2Game_GetItemsRequest());
            if (response.ErrorCode == ErrorCode.Success)
            {
                Items.AddRange(response.Items);
                Rigs.AddRange(response.Rigs);
                Slots.AddRange(response.Slots);

                UpdateBindData();
                Log.Info(
                    $"获取背包数据成功！Items={JsonConvert.SerializeObject(Items)} Rigs={JsonConvert.SerializeObject(Rigs)}");
            }
        }

        #region 获取物品列表

        public List<ItemInfo> GetItemsByType(ItemType itemType)
        {
            return Items.Where(item => item.ItemType == itemType).ToList();
        }

        public Dictionary<ItemType, List<ItemInfo>> GetItemsByType(bool ignoreBind = true)
        {
            var dic = new Dictionary<ItemType, List<ItemInfo>>();
            foreach (var item in Items)
            {
                if (BindId.Contains(item.Id)) continue;
                var type = item.ConfigId.GetItemType();
                if (!dic.ContainsKey(type))
                {
                    dic.Add(type, new List<ItemInfo>());
                }

                dic[type].Add(item);
            }

            foreach (var (key, list) in dic)
            {
                list.Sort((x, y) => (int)(y.Config.Quality - x.Config.Quality));
            }

            return dic;
        }

        public List<object> GetItemListData(params ItemType[] itemTypes)
        {
            var dic = GetItemsByType();

            if (itemTypes == null || itemTypes.Length == 0)
            {
                itemTypes = new ItemType[] { ItemType.Rod, ItemType.Bobber, ItemType.Reel };
            }

            List<object> items = new List<object>();

            foreach (var (type, list) in dic)
            {
                if (!itemTypes.Contains(type)) continue;
                var typeItem = new ClassifyListTitleData()
                {
                    Title = type.ToString()
                };
                items.Add(typeItem);
                items.AddRange(list);
            }

            return items;
        }

        #endregion

        public List<ItemInfo> GetBindItems(long itemId)
        {
            List<ItemInfo> ret = new List<ItemInfo>();
            var bind = Rigs.Find(t => t.Item == itemId);
            if (bind != null)
            {
                ret.AddRange(bind.BindItems.Select(bindId => Items.Find(t => t.Id == bindId)));
            }

            return ret;
        }
        

        #region 数据操作

        #region 配件

        public async FTask RemoveRig(long id, long rig)
        {
            var response = (Game2C_RigChangeResponse)await Net.Call(new C2Game_RigChangeRequest()
            {
                ItemId = id,
                RigId = rig,
            });
            Log.Info($"移除配件结果={response.ErrorCode}");
            if (response.ErrorCode == ErrorCode.Success)
            {
                SetBindItemData(id, response.Rigs);
                Notices.Show("配件变更成功");
            }
            else
            {
                Notices.Error("配件变更失败");
            }
        }

        public async FTask AddRig(long id, long rig, long old = 0)
        {
            var response = (Game2C_RigChangeResponse)await Net.Call(new C2Game_RigChangeRequest()
            {
                ItemId = id,
                RigId = rig,
                OldRigId = old,
                IsAdd = true
            });
            Log.Info($"更换配件结果={response.ErrorCode}");
            if (response.ErrorCode == ErrorCode.Success)
            {
                SetBindItemData(id, response.Rigs);
                Notices.Show("配件变更成功");
            }
            else
            {
                Notices.Error("配件变更失败");
            }
        }


        private void UpdateBindData()
        {
            BindId.Clear();
            foreach (var rig in Rigs)
            {
                foreach (var rigBindItem in rig.BindItems)
                {
                    BindId.Add(rigBindItem);
                }
            }
        }

        private void SetBindItemData(long id, ItemBindInfo rigData)
        {
            var oldRigData = Rigs.Find(t => t.Item == id);
            if (oldRigData != null)
            {
                oldRigData.BindItems.Clear();
                oldRigData.BindItems.AddRange(rigData.BindItems);
            }
            else
            {
                Rigs.Add(rigData);
            }

            UpdateBindData();
        }

        #endregion

        #region 插槽

        public ItemInfo GetSlotItem(int index)
        {
            if (index < Slots.Count && index >= 0)
            {
                var itemId = Slots[index];
                if (itemId > 0)
                {
                    return Items.Find(t => t.Id == itemId);
                }
            }

            return null;
        }

        public async FTask SetSlot(int index, long id)
        {
            var response = (Game2C_SetSlotResponse)await Net.Call(new C2Game_SetSlotRequest()
            {
                Index = index,
                Id = id
            });
            Log.Info($"设置插槽结果={response.ErrorCode},参数 index={index} id={id}");
            if (response.ErrorCode == ErrorCode.Success)
            {
                Slots.Clear();
                Slots.AddRange(response.Slots);
                // SetBindItemData(id, response.Rigs);
                Notices.Show("插槽设置成功");
            }
            else
            {
                Notices.Error("插槽设置失败");
            }
        }

        #endregion

        #endregion

        #endregion
    }
}