using System;
using System.Collections.Generic;
using System.Linq;

namespace GameFix.Poker
{
    /// <summary>
    /// 桌面牌组管理
    /// </summary>
    public class Deck : List<Card>, ICardIdResolver
    {
        public static readonly Random Random = new Random();
        
        public new Card this[int index] => (Card)base[index];

        public IStyleComparer StyleComparer => mBaseLogic.GetStyleComparer();
        
        public DeckSerializer Serializer {get; private set;}

        private DeckBaseLogic mBaseLogic;

        internal Deck(DeckBaseLogic baseLogic) : base(baseLogic.Create())
        {
            mBaseLogic = baseLogic;
            Serializer = new DeckSerializer(this);
        }

        public T GetDeckLogic<T>()
        {
            if (mBaseLogic is T logic)
                return logic;
            return default;
        }

        public IEnumerable<Card> GetCards(Func<Card, bool> predicate)
        {
            return this.Where(predicate);
        }
        
        public List<Card> GetCards(IEnumerable<int> ids)
        {
            List<Card> cards = new List<Card>();
            var enumerable = ids.ToList();
            for (int i = 0; i < enumerable.Count(); i++)
            {
                var card = GetById(enumerable.ElementAt(i));
                if (card != null)
                    cards.Add(card);
            }
        
            return cards;
        }
        
        public Card GetCard(byte suit, int value)
        {
            return GetCards(p=>p.Suit == suit && p.Value == value).FirstOrDefault();
        }
        
        public Card GetCard(byte suit, int value, Func<Card, bool> condition)
        {
            return GetCards(p=>p.Suit == suit && p.Value == value)
                .Where(condition).FirstOrDefault();
        }
        
        public Card GetById(int id)
        {
            if (id < 0 || id >= Count) return null;
            return this[id];
        }

        public void RevertAllCardType()
        {
            for (int i = 0; i < this.Count; i++)
            {
                this[i].CardType = DataCardConst.CardTypeNormal;
            }
        }
        
        /// <summary>
        /// 刷新牌类型
        /// </summary>
        public void RefreshCardType(byte cardType, List<Card> cards)
        {
            RevertAllCardType();
            for (int i = 0; i < cards.Count; i++)
            {
                int index = this.IndexOf(cards[i]);
                if (index >= 0)
                    this[index].CardType = cardType;
            }
        }
        
        public void RefreshCardType(byte cardType, List<int> ids)
        {
            RevertAllCardType();
            for (int i = 0; i < ids.Count; i++)
            {
                var card = GetById(ids[i]);
                if (card != null)
                    card.CardType = cardType;
            }
        }
        
        public void RefreshCardType(byte cardType, List<byte> values)
        {
            RevertAllCardType();
            for (int i = 0; i < this.Count; i++)
            {
                if (values.Contains(this[i].Value))
                    this[i].CardType = cardType;
            }
        }
        
        /// <summary>
        /// 将牌列表封装成牌组，可用于牌型等判断
        /// </summary>
        public CardGroup CreateCardGroup(IEnumerable<Card> cards)
        {
            var cardGroup = new CardGroup(cards, this);
            var styleHelpers = mBaseLogic.GetAllStyleHelper(cardGroup);
            var styleComparer = mBaseLogic.GetStyleComparer();
            cardGroup.RegisterHelper(styleHelpers);
            cardGroup.RegisterStyleComparer(styleComparer);
            return cardGroup;
        }
        
        public CardHandGroup CreateCardHandGroup(IEnumerable<Card> cards)
        {
            var cardGroup = new CardHandGroup(cards, this);
            var styleHelpers = mBaseLogic.GetAllStyleHelper(cardGroup);
            var styleComparer = mBaseLogic.GetStyleComparer();
            cardGroup.RegisterHelper(styleHelpers);
            cardGroup.RegisterStyleComparer(styleComparer);
            return cardGroup;
        }
        
        public static Deck Create(DeckBaseLogic baseLogic)
        {
            var deck = new Deck(baseLogic);
            baseLogic.SetDeck(deck);
            baseLogic.OnInit();
            return deck;
        }
    }
}