using System.Collections.Generic;
using System.Text;
using MessagePack;

namespace GameMessage.JJZhaDan
{
    [MessagePackObject]
    public struct CardPack
    {
        /// <summary>
        /// 4个玩家手牌
        /// </summary>
        [Key(0)]
        public PlayCard[] PlayCard;
        public void Init()
        {
            PlayCard = new PlayCard[4];
        }
    }
    
    [MessagePackObject]
    public struct PlayCard
    {
        /// <summary>
        /// 1个玩家的手牌
        /// </summary>
        [Key(0)]
        public TCardInfo[] CardInfos;
        /// <summary>
        /// 初始化玩家牌
        /// </summary>
        public void Init(int len)
        {
            CardInfos = new TCardInfo[len];
        }
    }
    
    [MessagePackObject]
    public struct TCardInfo : ICardInfoType1
    {
        /// <summary>
        /// 绝对ID
        /// </summary>
        [Key(0)]
        public byte ID { get; set; }

        /// <summary>
        /// 牌面花色 1黑桃 2红桃 3梅花 4方块 5大小王
        /// </summary>
        [Key(1)] public byte Flower;

        /// <summary>
        /// 牌面大小
        /// 1-13 黑桃A-K
        /// 14-26 红桃A-K
        /// 27-39 梅花A-K
        /// 40-52 方块A-K
        /// 53小王 54大王
        /// </summary>
        [Key(2)]
        public byte Num { get; set; }

        /// <summary>
        /// 游戏里大小 3-14（3~A） 16是2  98小王 100大王
        /// </summary>
        [Key(3)]
        public byte GameNum { get; set; }

        /// <summary>
        /// 游戏分值
        /// </summary>
        [Key(4)] public byte Score;

        /// <summary>
        /// 当前在谁手里 1-4
        /// </summary>
        [Key(5)] public byte GameOwer;

        /// <summary>
        /// 状态 0打下去了 1没有打下去
        /// </summary>
        [Key(6)] public byte GameState;

        public override string ToString()
        {
            return
                $"ID:{ID} 花色:{(Flower == 1 ? "黑桃" : Flower == 2 ? "红桃" : Flower == 3 ? "梅花" : Flower == 4 ? "方块" : "王")} 大小:{Num}_{GameNum} 分:{Score} 状态:{(GameState == 1 ? "在手上" : "打下去了")}";
        }

        public bool IsActive()
        {
            return ID > 0 && Flower > 0 && GameNum > 0;
        }

        public override bool Equals(object obj)
        {
            if (!(obj is TCardInfo))
            {
                return false;
            }

            TCardInfo other = (TCardInfo)obj;
            return /*ID == other.ID &&*/
                Flower == other.Flower &&
                Num == other.Num &&
                GameNum == other.GameNum &&
                Score == other.Score &&
                GameOwer == other.GameOwer &&
                GameState == other.GameState;
        }

        public override int GetHashCode()
        {
            int hash = 17;
            //hash = hash * 23 + ID.GetHashCode();
            hash = hash * 22 + Flower.GetHashCode();
            hash = hash * 33 + Num.GetHashCode();
            hash = hash * 24 + GameNum.GetHashCode();
            hash = hash * 11 + Score.GetHashCode();
            hash = hash * 12 + GameOwer.GetHashCode();
            hash = hash * 15 + GameState.GetHashCode();
            return hash;
        }
    }
    
    [MessagePackObject]
    public struct PlayOutCard : IPlayOutCardType1
    {
        /// <summary>
        /// 牌的位置从1开始
        /// </summary>
        [Key(0)]
        public byte Pos;

        /// <summary>
        /// 牌的类型
        /// </summary>
        [Key(1)]
        public CardType1 Type { get; set; }

        /// <summary>
        /// 牌大小-运算大小
        /// 正的510K 数值是21，副的510K是20
        /// </summary>
        [Key(2)]
        public byte GameNum { get; set; }

        /// <summary>
        /// 出的牌绝对Id集合
        /// </summary>
        [Key(3)]
        public byte[] Ids { get; set; }

        public void Init(int len)
        {
            Ids = new byte[len];
        }

        public override string ToString()
        {
            return $"pos:{Pos} type:{Type} num:{GameNum} ids:{(Ids == null || Ids.Length <= 0 ? "不要" :($"len:{Ids.Length}--{string.Join(",", Ids)}"))}";
        }
    }
    
    [MessagePackObject]
    public struct JJBombGamePack
    {

        [Key(0)]
        public JJBombLogicInfo Info;

        /// <summary>
        /// 牌的内存包
        /// </summary>
        [Key(1)]
        public CardPack CardPack;
        /// <summary>
        /// 规则
        /// </summary>
        [Key(2)]
        public Rule Rule;

        public void Init()
        {
            Info.Init();
            CardPack.Init();
        }
    }

    [MessagePackObject]
    public struct JJBombLogicInfo
    {
        /// <summary>
        /// 游戏流程 1游戏开始 2加买 3发牌 4独打 5叫牌 6打牌 7结算
        /// </summary>
        [Key(0)]
        public byte GameZT;
        /// <summary>
        /// 控制权是哪个位置1-4
        /// </summary>
        [Key(1)]
        public byte WhoPlay;

        /// <summary>
        /// 最大的出牌内容
        /// </summary>
        [Key(2)]
        public PlayOutCard MaxPlayCard;

        /// <summary>
        /// 当前出牌内容
        ///  单张、对子、连对、三张、三带二、飞机、飞机带对子、炸弹、顺子
        /// </summary>
        [Key(3)]
        public PlayOutCard ActivePlayCard;

        /// <summary>
        /// 第一个出牌位置
        /// </summary>
        [Key(4)]
        public byte FistPlay;

        /// <summary>
        /// 叫牌的牌Id,叫牌的时候就赋值进去
        /// </summary>
        [Key(5)]
        public byte[] JiaoCard;

        /// <summary>
        /// 记录打完牌的位置 0号位置是头游 1号位置是二游 2-三游 3-四游
        /// </summary>
        [Key(6)]
        public byte[] OverPos;

        /// <summary>
        /// 谁和谁是队友 
        /// 存储队友2个位置，从1开始，如果第二个位置是100以上，说明暗牌那个玩家还没有打下来
        /// 如果玩家是一打三，那第一个位置就是玩家自己的位置。第二个位置就是100（没有这个位置所以就表示他没有队友，就是一打三）
        /// </summary>
        [Key(7)]
        public byte[] DuiYouPos;

        /// <summary>
        /// 存储要计算的彩分排序
        /// 普通玩法要打下来才计算，炸弹模式只计算玩家手里的炸弹        
        /// </summary>
        [Key(8)]
        public List<PlayOutCard> CaiCards;

        /// <summary>
        /// 4个玩家的彩分。打牌过程中是多少结算直接用
        /// </summary>
        [Key(9)]
        public sbyte[] CaiScore;

        /// <summary>
        /// 玩家的彩的数量
        /// </summary>
        [Key(10)]
        public byte[] CaiNum;

        /// <summary>
        /// 加买分
        /// </summary>
        [Key(11)]
        public sbyte[] BuyScore;

        /// <summary>
        /// 玩家选择的加买 0是不买 1买1分 2买2分
        /// </summary>
        [Key(12)]
        public byte[] BuyNum;

        /// <summary>
        /// 牌局输赢分，炸弹玩法该值没有
        /// </summary>
        [Key(13)]
        public sbyte[] PlayScore;

        /// <summary>
        /// 玩家托管标识 0没有托管 1托管中
        /// </summary>
        [Key(14)]
        public byte[] PlayTuoGauan;

        /// <summary>
        /// 玩家是否独打 0就是还没做操作 1不独打 2独打
        /// </summary>
        [Key(15)]
        public byte[] DuDa;

        /// <summary>
        /// 玩家是否买 0就是还没做操作 1不买 2买
        /// </summary>
        [Key(16)]
        public byte[] Buy;

        /// <summary>
        /// 存储玩家买操作，目的是让4个玩家同时可以操作
        /// 0没有操作  1不买 2买
        /// </summary>
        [Key(17)]
        public byte[,] BuyCZ;

        public void Init()
        {
            MaxPlayCard = new PlayOutCard();
            ActivePlayCard = new PlayOutCard();
            OverPos = new byte[4];
            DuiYouPos = new byte[2];
            JiaoCard = new byte[2];
            CaiCards = new List<PlayOutCard>();
            CaiCards.Clear();
            CaiNum = new byte[4];
            CaiScore = new sbyte[4];
            BuyScore = new sbyte[4];
            PlayScore = new sbyte[4];
            PlayTuoGauan = new byte[4];
            BuyNum = new byte[4];
            DuDa = new byte[4];
            Buy = new byte[4];
            BuyCZ = new byte[4, 1];
        }
    }

    /// <summary>
    /// 九江炸弹玩法规则
    /// </summary>
    [MessagePackObject]
    public struct Rule
    {
        /// <summary>
        /// 是否是炸弹玩法 true是 false是普通玩法。炸弹玩法不打牌，直接发牌完进入结算。也没有发牌前的加买选择
        /// </summary>
        [Key(0)]
        public bool IsBomb;
        /// <summary>
        /// 是否自动叫牌 true自动叫牌 false玩家自己手动叫牌（手动叫牌不能叫自己手里有的牌）
        /// </summary>
        [Key(1)]
        public bool IsAutoJiaoCard;

        /// <summary>
        /// 是否显示剩余牌 true显示 false不显示，到了报牌在显示
        /// </summary>
        [Key(2)]
        public bool IsShowShengYuCard;

        /// <summary>
        /// 0不买 1买1 2买2
        /// </summary>
        [Key(3)]
        public byte BuyNum;

        /// <summary>
        /// 是否每局加买 true是 false不是 
        /// </summary>
        [Key(4)]
        public bool IsEachBuy;

        /// <summary>
        /// 是否保底 true保 false不保
        /// 保底的话在原有基础上加1分 比如以前赚1分，变成赚2分。以前输1分变成输2分
        /// </summary>
        [Key(5)]
        public bool IsBaoDi;

        /// <summary>
        /// 是否支持顺子 true支持 false不支持
        /// </summary>
        [Key(6)]
        public bool IsShunZi;

        /// <summary>
        /// 是否可以看队友牌 true可以 false不可以
        /// </summary>
        [Key(7)]
        public bool IsCanLook;

        /// <summary>
        /// 飞机最后一手可以少带  true可以 false不可以 （少带也是带对子）
        /// </summary>
        [Key(8)]
        public bool AircraftLessCard;

        /// <summary>
        /// 报牌数量
        /// </summary>
        [Key(9)]
        public int BaoPai;

        /// <summary>
        /// 托管的时间 0不托管 1超过1分钟托管 3超过3分钟托管 5超过5分钟托管
        /// </summary>
        [Key(10)]
        public int TuoGuanNum;

        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();

            sb.Append(IsBomb ? "炸弹玩法 " : "普通玩法 ");
            if (!IsBomb)
            {
                sb.Append(IsAutoJiaoCard ? "自动叫牌 " : "手动叫牌 ");
                if (IsShowShengYuCard)
                {
                    sb.Append("显示剩余牌 ");
                }
                if (BuyNum > 0)
                {
                    sb.Append($"买{BuyNum} ");
                }
                sb.Append(IsEachBuy ? "每局加买 " : "首局加买 ");
                sb.Append(IsBaoDi ? "头名1分保底 " : "头名不保底 ");
                if (IsShunZi)
                {
                    sb.Append("可顺子 ");
                }
                if (AircraftLessCard)
                {
                    sb.Append("飞机最后一手可以少带 ");
                }
                if (IsCanLook)
                {
                    sb.Append("看队友牌 ");
                }
                if (TuoGuanNum > 0)
                {
                    sb.Append(TuoGuanNum + "分钟托管 ");
                }
                sb.Append($"报牌{BaoPai}张 ");
            }
            return sb.ToString();
        }
    }

    
}
