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

namespace GameFix.Poker
{
    /// <summary>
    /// 连炸 （3连以上）
    /// CardStyleInfo.CustomInt: 表示几个相同炸弹组成 
    /// </summary>
    public class CardStyleBomb123Helper : CardStyleBaseHelper
    {
        public override int CardStyle => DataCardConst.CardStyleBomb123;
        public override int CardCnt => 12;

        internal override bool CheckStyleNormal(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
        {
            cardStyleInfo = null;
            if (group.Cards.Count >= CardCnt)
            {
                var keysCnt = group.CardGroupDic.Keys.Count;
                if (keysCnt != 1) return false;
                var bombSize = group.CardGroupDic.Keys.First(); // 单个炸弹的大小
                if (bombSize < 4) return false;
                
                // 判断是否连续
                if (IsContinuous(group.CardGroupList, bombSize, out var shunCnt)
                    && shunCnt.Count * bombSize == group.Cards.Count)
                {
                    cardStyleInfo = CardStyleHelper.CreateCardStyleInfo(CardStyle, group.Cards);
                    cardStyleInfo.CustomInt =  group.Cards.Count / bombSize;
                    return true;
                }
            }
            
            return false;
        }

        internal override bool CheckStyleWithLZ(CardBaseGroup group, out CardStyleInfo cardStyleInfo)
        {
            cardStyleInfo = null;
            if (group.Cards.Count < CardCnt) return false;
            var lzCnt = group.LZCards.Count;
            var bombSize = group.CardGroupDic.Keys.Max(); // 最大的数量作为单个炸弹的大小
            if (bombSize < 4) lzCnt -= (bombSize - 4);
            if (lzCnt < 0) return false;
            
            for (int i = 0; i < group.CardGroupDic.Keys.Count; i++)
            {
                var key = group.CardGroupDic.Keys.ElementAt(i);
                var vList = group.CardGroupDic[key];
                var diffSize = bombSize - key;
                lzCnt -= diffSize * vList.Count;
                
                if (lzCnt < 0) return false;
            }
            
            // 判断是否连续
            if (IsMaxContinuousByLZ(group.CardGroupList, bombSize, group.LZCards.Count,
                    out var shunValueList, out var lackValueList)
                && shunValueList.Count * bombSize == group.Cards.Count)
            {
                cardStyleInfo = new CardStyleInfo(CardStyle, shunValueList[0], shunValueList.Count * bombSize);
                cardStyleInfo.CardLackValues = lackValueList.ToArray();
                cardStyleInfo.CustomInt =  group.Cards.Count / bombSize;

                return true;
            }

            return false;
        }

        internal override List<CardGroupList> GetAllEatTipGroup(CardBaseGroup group, CardStyleInfo eatStyleInfo)
        {
            var groupCnt = group.CardGroupList.Count;
            var groupList = new List<CardGroupList>(groupCnt);
            
            // 找最大的连炸
            List<Card> continuousList = new List<Card>();
            int minBombSize = Int32.MaxValue;
            for (int i = 0; i < group.CardGroupList.Count; i++)
            {
                if (group.CardGroupList[i].Count >= 4)
                {
                    minBombSize = Math.Min(minBombSize, group.CardGroupList[i].Count);
                    continuousList.AddRange(group.CardGroupList[i]);
                } else if (continuousList.Count >= CardCnt)
                {
                    // 把一些多余的牌删除
                    var filterList = continuousList.GroupBy(c=>c.Value)
                        .Select(g=>
                            Tuple.Create(g.Key,g.ToList().GetRange(0, minBombSize)))
                        .SelectMany(g=>g.Item2)
                        .ToList();
                    
                    // 判断是否属于连炸
                    var targetGroup = group.mDeck.CreateCardGroup(filterList);
                    if (targetGroup.GetCardStyleInfo().CardStyle == CardStyle)
                    {
                        groupList.Add(new CardGroupList(filterList));
                    }
                    
                    minBombSize = Int32.MaxValue;
                    continuousList.Clear();
                }
                else if (continuousList.Count > 0)
                {
                    minBombSize = Int32.MaxValue;
                    continuousList.Clear();
                }
            }
            
            return groupList;
        }

        internal override List<CardGroupList> GetAllEatTipGroupWithLZ(CardBaseGroup group, CardStyleInfo eatStyleInfo)
        {
            var groupList = new List<CardGroupList>();
            
            // 找最大的连炸
            List<Card> continuousList = new List<Card>();
            int lzCnt = group.LZCards.Count;
            int continuousCnt = 0;
            // 2233344444555
            for (int i = 0; i < group.CardGroupList.Count; i++)
            {
                continuousList.Clear();
                continuousCnt = 0;
                for (int j = 0; j < group.CardGroupList.Count; j++)
                {
                    var index = i + j;
                    if (index >= group.CardGroupList.Count) break;
                    if (group.CardGroupList[index].Count == 0) break;

                    if (group.CardGroupList[index].Count >= 4
                        || group.CardGroupList[index].Count + lzCnt >= 4)
                    {
                        continuousList.AddRange(group.CardGroupList[index]);
                        continuousCnt++;
                        if (continuousCnt >= 3)
                        {
                            groupList.Add(new CardGroupList(continuousList));
                        }
                    } else
                    {
                        continuousList.Clear();
                        continuousCnt = 0;
                    }
                }
            }
            
            // 继续检查每个连炸是否符合要求
            for (int i = groupList.Count - 1; i >= 0 ; i--)
            {
                var bomb = groupList[i];
                var bombDict = bomb.GroupBy(c => c.Value)
                    .ToDictionary(g => g.Key, g => g.ToList());
                var bombLine = bombDict.Values.Select(g => g.Count).ToList();
                var bombMax = bombLine.Max();
                int needCnt = 0;
                if (bombMax >= 4)
                {
                    int oldBomMax = bombMax;
                    while (bombMax >= 4)
                    {
                        needCnt = 0;
                        for (int j = 0; j < bombLine.Count; j++)
                        {
                            needCnt += bombMax - bombLine[j];
                        }
                        
                        if (needCnt <= lzCnt) break;
                        bombMax--;
                    }

                    if (needCnt > lzCnt)
                    {
                        groupList.RemoveAt(i);
                        continue;
                    }
                    
                    // 删除多余得牌
                    foreach (var bd in bombDict)
                    {
                        var rmCards = bd.Value.GetRange(0, oldBomMax - bombMax);
                        for (int j = rmCards.Count - 1; j >= 0 ; j--)
                        {
                            bomb.Remove(rmCards[j]);
                        }
                    }
                }
                else
                {
                    for (int j = 0; j < bombLine.Count; j++)
                    {
                        needCnt += 4 - bombLine[j];
                    }

                    if (needCnt > lzCnt)
                    {
                        groupList.RemoveAt(i);
                        continue;
                    }
                }
                
                // 再检验一次
                bomb.AddRange(group.LZCards.GetRange(0, needCnt));
                var bombGroup = group.mDeck.CreateCardGroup(bomb);
                if (bombGroup.GetCardStyleInfo().CardStyle != CardStyle)
                {
                    groupList.RemoveAt(i);
                }
            }
            
            return groupList;
        }
    }
}