using System;
using MessagePack;
using Newtonsoft.Json;

namespace GameMessage.DouDiZhuG
{
    public static class ConstData
    {
        public const int CardCount = 54;

        /// <summary>
        /// 底牌数量
        /// </summary>
        public const int BackCardCnt = 3;

        /// <summary>
        /// 
        /// </summary>
        public const int MaxPlayerCnt = 3;

        /// <summary>
        /// 最大出牌的数量
        /// </summary>
        public const int MaxOutCardCnt = 20;

        /// <summary>
        /// 最大手牌数量
        /// </summary>
        public const int MaxShouPaiCnt = 20;

        /// <summary>
        /// 无
        /// </summary>
        public const byte GameStateNone = 0;

        /// <summary>
        /// 游戏开始
        /// </summary>
        public const byte GameStateStart = 10;

        /// <summary>
        /// 抢地主
        /// </summary>
        public const byte GameStateGrab = 11;

        /// <summary>
        /// 叫分
        /// </summary>
        public const byte GameStateCall = 30;

        /// <summary>
        /// 翻底牌
        /// </summary>
        public const byte GameStateFanDiPai = 40;

        /// <summary>
        /// 打牌
        /// </summary>
        public const byte GameStatePlaying = 60;

        /// <summary>
        /// 无人叫分
        /// </summary>
        public const byte GameStateNoOneCall = 70;

        /// <summary>
        /// 游戏结算
        /// </summary>
        public const byte GameStateSettlement = 80;

        /// <summary>
        /// 黑桃
        /// </summary>
        public const byte SuitSpade = 1;

        /// <summary>
        /// 红桃
        /// </summary>
        public const byte SuitHeart = 2;

        /// <summary>
        /// 梅花
        /// </summary>
        public const byte SuitClub = 3;

        /// <summary>
        /// 方块
        /// </summary>
        public const byte SuitDiamond = 4;

        /// <summary>
        /// 王
        /// </summary>
        public const byte SuitJoker = 5;

        /// <summary>
        /// 无牌型
        /// </summary>
        public const byte CardStyle0 = 0;

        /// <summary>
        /// 单张
        /// </summary>
        public const byte CardStyle1 = 1;

        /// <summary>
        /// 对子
        /// </summary>
        public const byte CardStyle2 = 2;

        /// <summary>
        /// 三张
        /// </summary>
        public const byte CardStyle3 = 3;

        /// <summary>
        /// 四张
        /// </summary>
        public const byte CardStyle4 = 4;

        /// <summary>
        /// 火箭
        /// </summary>
        public const byte CardStyle5 = 5;

        /// <summary>
        /// 顺子
        /// </summary>
        public const byte CardStyle123 = 6;

        /// <summary>
        /// 双顺
        /// </summary>
        public const byte CardStyle112233 = 7;

        /// <summary>
        /// 三顺
        /// </summary>
        public const byte CardStyle111222 = 8;

        /// <summary>
        /// 三带一
        /// </summary>
        public const byte CardStyle31 = 9;

        /// <summary>
        /// 三带对
        /// </summary>
        public const byte CardStyle32 = 10;

        /// <summary>
        /// 四带两张或者一对
        /// </summary>
        public const byte CardStyle41 = 11;

        /// <summary>
        /// 四带两对
        /// </summary>
        public const byte CardStyle42 = 12;

        /// <summary>
        /// 飞机带单张
        /// </summary>
        public const byte CardStyle331 = 13;

        /// <summary>
        /// 飞机带对子
        /// </summary>
        public const byte CardStyle332 = 14;

        /*/// <summary>
        /// 连炸
        /// </summary>
        // public const byte CardStyle44 = 15;*/

        /// <summary>
        /// 操作类型之叫分
        /// </summary>
        public const int OperateTypeScore = 1;

        /// <summary>
        /// 操作类型之出牌
        /// </summary>
        public const int OperateTypeOutCard = 2;

        /// <summary>
        /// 叫分操作的时间
        /// </summary>
        public const int OperateTypeScoreTime = 16;

        /// <summary>
        /// 出牌操作时间
        /// </summary>
        public const int OperateTypeOutCardTime = 20;

        /// <summary>
        /// 要不起时的出牌操作时间
        /// </summary>
        public const int OperateTypePassOutCardTime = 3;

        public static readonly byte[] CardNums = new byte[]
        {
            14, 16, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13
        };

        public static readonly byte[] JokerNums = new byte[]
        {
            18, 19
        };
    }

#if Server
    public interface ITotalCount
    {
        /// <summary>
        /// 总数量
        /// </summary>
        int Total { get; }
    }

    /// <summary>
    /// 表示纸牌
    /// </summary>
    public interface ICard : IComparable<ICard>, IEquatable<ICard>, ITotalCount
    {
        /// <summary>
        /// 绝对ID
        /// 范围 0-53
        /// </summary>
        int Id { get; }

        /// <summary>
        /// 初始在谁手里
        /// 范围 1，2，3，底牌为10
        /// </summary>
        sbyte GameInitOwer { get; }

        /// <summary>
        /// 当前在谁手里
        /// </summary>
        sbyte GameOwer { get; }

        /// <summary>
        /// 游戏中状态
        /// 0表示未打出，11表示此牌已打出
        /// </summary>
        byte GameState { get; }

        /// <summary>
        /// 纸牌点值
        /// </summary>
        byte Value { get; }

        /// <summary>
        /// 纸牌花色
        /// </summary>
        byte Suit { get; }

        ICard Clone();
    }
#endif

    public class DouDiZhuGCard
#if Server
        : ICard
#endif
    {
        public int Id { get; set; } // 绝对ID

        /// <summary>
        /// 花色 
        /// </summary>
        public byte Flower { get; set; }

        /// <summary>
        /// 逻辑数  范围(3-A:3-14) (16:2 18:小王 19:大王)
        /// </summary>
        public byte LogicNum { get; set; } // 牌面大小               游戏端未使用       牌点数 范围(3-A:3-14) (2-王:16-18)

        /// <summary>
        /// 显示数 1 - 13 (A-K) 14小王 15大王
        /// </summary>
        public byte Num { get; set; }

        /// <summary>
        /// 排序数
        /// </summary>
        public int SortNum { get; set; }

        public DouDiZhuGCard()
        {
        }

        public override string ToString()
        {
            var suitStr = string.Empty;
            switch (Flower)
            {
                case ConstData.SuitSpade:
                    suitStr = "黑";
                    break;
                case ConstData.SuitHeart:
                    suitStr = "红";
                    break;
                case ConstData.SuitClub:
                    suitStr = "梅";
                    break;
                case ConstData.SuitDiamond:
                    suitStr = "方";
                    break;
                case ConstData.SuitJoker:
                    return (LogicNum == 18 ? "小王" : "大王");
                default:
                    throw new ArgumentOutOfRangeException(nameof(Flower));
            }

            var valueStr = string.Empty;
            switch (LogicNum)
            {
                case 3:
                case 4:
                case 5:
                case 6:
                case 7:
                case 8:
                case 9:
                case 10:
                    valueStr = LogicNum.ToString().PadRight(2, ' ');
                    break;
                case 11:
                    valueStr = "J ";
                    break;
                case 12:
                    valueStr = "Q ";
                    break;
                case 13:
                    valueStr = "K ";
                    break;
                case 14:
                    valueStr = "A ";
                    break;
                case 16:
                    valueStr = "2 ";
                    break;
                default:
                    throw new ArgumentOutOfRangeException(nameof(LogicNum));
            }

            return suitStr + valueStr;
        }

#if Server
        [JsonIgnore] public sbyte GameOwer { get; set; } = -1; // 当前在谁手里(范围 0,1,2,3 10表示底牌 -1表示不在任何人手里)
        [JsonIgnore] public sbyte GameInitOwer { get; set; } = -1; // 初始在谁手里(同上)
        [JsonIgnore] public byte GameState { get; set; } = 0; // 游戏中状态 0表示未打出，11表示此牌已打出

        public byte Value => LogicNum;
        public byte Suit => Flower;


        public int CompareTo(ICard other)
        {
            if (Value == other.Value)
            {
                return 0;
            }

            return Value > other.Value ? 1 : -1;
        }

        public static bool operator ==(DouDiZhuGCard x, DouDiZhuGCard y)
        {
            var xIsNull = object.Equals(x, null);
            var yIsNull = object.Equals(y, null);
            if (xIsNull && yIsNull)
            {
                return true;
            }
            else if (xIsNull || yIsNull)
            {
                return false;
            }
            else if (ReferenceEquals(x, y))
            {
                return true;
            }
            else
            {
                return x.GetHashCode() == y.GetHashCode();
            }
        }

        public static bool operator !=(DouDiZhuGCard x, DouDiZhuGCard y)
        {
            return !(x == y);
        }

        /// <summary>
        /// 比较牌值大小
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        public static bool operator >(DouDiZhuGCard x, DouDiZhuGCard y)
        {
            return x.Value > y.Value;
        }

        /// <summary>
        /// 比较牌值大小
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        public static bool operator <(DouDiZhuGCard x, DouDiZhuGCard y)
        {
            return x.Value < y.Value;
        }

        int? _hashCode = null;

        public override int GetHashCode() =>
            _hashCode.HasValue ? _hashCode.Value : (_hashCode = Id << 16 | (byte)Flower << 8 | LogicNum).Value;


        public override bool Equals(object obj)
        {
            var card = obj as DouDiZhuGCard;
            if (card != null)
            {
                return Equals(card);
            }

            return false;
        }

        public bool Equals(ICard other)
        {
            if (other == null)
            {
                return false;
            }
            else if (ReferenceEquals(this, other))
            {
                return true;
            }
            else
            {
                return this.GetHashCode() == other.GetHashCode();
            }
        }

        string Text => ToString();

        public int Total => 1;

        public ICard Clone() => (ICard)MemberwiseClone();

#endif
    }

    [MessagePackObject]
    public class DdzPlayerInfo
    {
        /// <summary>
        /// 出牌的数量
        /// </summary>
        [Key(0)] public int OutCardCnt;

        /// <summary>
        /// 最大出牌的数量
        /// </summary>
        [Key(1)] public int[] OutCardIds;

        /// <summary>
        /// 出的牌型
        /// </summary>
        [Key(2)] public CardStyleInfo CardStyleInfo;

        /// <summary>
        /// 手里的牌数量
        /// </summary>
        [Key(3)] public int ShouPaiCnt;

        /// <summary>
        /// 手里的牌
        /// </summary>
        [Key(4)] public int[] ShouPaiIds;

        /// <summary>
        /// 玩家叫分数量
        /// </summary>
        [Key(5)] public int Score;

        /// <summary>
        /// 输赢分
        /// </summary>
        [Key(6)] public int WinMoney;

        /// <summary>
        /// 出牌的次数
        /// </summary>
        [Key(7)] public int OutCardTime;

        public DdzPlayerInfo()
        {
            OutCardIds = new int[ConstData.MaxOutCardCnt];
            ShouPaiIds = new int[ConstData.MaxShouPaiCnt];
        }

        public void Init()
        {
            OutCardCnt = 0;
            CardStyleInfo = new CardStyleInfo();
            ShouPaiCnt = 0;
            Score = -1;
            WinMoney = 0;
            OutCardTime = 0;
        }
    }

    /// <summary>
    /// 斗地主数据
    /// </summary>
    [MessagePackObject]
    public class DdzGameData
    {
        /// <summary>
        /// 是否是重连
        /// </summary>
        [Key(0)] public int Reconnect;

        /// <summary>
        /// 游戏当前状态
        /// </summary>
        [Key(1)] public int GameState;

        /// <summary>
        /// 上一个叫分的人
        /// </summary>
        [Key(2)] public int LastCallScoreRole;

        /// <summary>
        /// 谁可以操作
        /// </summary>
        [Key(3)] public int OptRole;

        /// <summary>
        /// 操作者可操作的时间x1000
        /// </summary>
        [Key(4)] public int OptRoleTime;

        /// <summary>
        /// 当前叫的分值
        /// </summary>
        [Key(5)] public int Score;

        /// <summary>
        /// 炸弹数量
        /// </summary>
        [Key(6)] public int BoomCnt;

        /// <summary>
        /// 上一个出牌操作者
        /// </summary>
        [Key(7)] public int LasOutOptRole;

        /// <summary>
        /// 上次出了牌的人 选不出的不算 这个是-1，那么就是第一个出牌的人,不是-1 只能出比这个人牌更大的牌
        /// </summary>
        [Key(8)] public int LastOutMen;

        /// <summary>
        /// 地主
        /// </summary>
        [Key(9)] public sbyte Banker;

        /// <summary>
        /// 第一个出完牌的人
        /// </summary>
        [Key(10)] public int FirstOutOver;

        /// <summary>
        /// 是否是春天
        /// </summary>
        [Key(11)] public bool IsChunTian;

        /// <summary>
        /// 底牌
        /// </summary>
        [Key(12)] public int[] LostCard;

        /// <summary>
        /// 玩家数据
        /// </summary>
        [Key(13)] public DdzPlayerInfo[] DdzPlayerInfos;

#if Server
        /// <summary>
        /// 54 张牌
        /// </summary>
        [JsonIgnore] [IgnoreMember] public DouDiZhuGCard[] Cards = new DouDiZhuGCard[ConstData.CardCount];
#endif

        public DdzGameData()
        {
            LostCard = new int[ConstData.BackCardCnt];
            DdzPlayerInfos = new DdzPlayerInfo[ConstData.MaxPlayerCnt];
        }

        public void Init()
        {
            for (int i = 0; i < DdzPlayerInfos.Length; i++)
            {
                DdzPlayerInfos[i] = new DdzPlayerInfo();
            }

            Score = 0;

            Banker = -1;
            OptRole = -1;
            LastOutMen = -1;
            LasOutOptRole = -1;
            LastCallScoreRole = -1;
            IsChunTian = false;
            BoomCnt = 0;

            for (int i = 0; i < DdzPlayerInfos.Length; i++)
            {
                DdzPlayerInfos[i].Init();
            }
        }
    }

    /// <summary>
    /// 牌型信息
    /// </summary>
    [MessagePackObject]
    public struct CardStyleInfo
    {
        /// <summary>
        /// 牌型
        /// </summary>
        [Key(0)] public int CardStyle;

        /// <summary>
        /// 关键牌 - 逻辑数
        /// </summary>
        [Key(1)] public int CardValue;

        /// <summary>
        /// 牌的数量
        /// </summary>
        [Key(2)] public int CardCnt;

        /// <summary>
        /// 对比牌型大小
        /// </summary>
        /// <param name="style1"></param>
        /// <param name="style2"></param>
        /// <returns></returns>
        public static bool operator >(CardStyleInfo style1, CardStyleInfo style2)
        {
            switch (style1.CardStyle)
            {
                case ConstData.CardStyle0:
                    return false;
                // case ConstData.CardStyle44: //连炸
                //     if (style2.CardStyle == style1.CardStyle)
                //     {
                //         if (style1.CardCnt > style2.CardCnt)
                //         {
                //             return true;
                //         }
                //         else if (style1.CardCnt < style2.CardCnt)
                //         {
                //             return false;
                //         }
                //         else
                //         {
                //             return style1.CardValue > style2.CardValue;
                //         }
                //     }
                //
                //     return false;
                case ConstData.CardStyle5: //王炸
                    // if (style2.CardStyle == ConstData.CardStyle44)
                    // {
                    //     return false;
                    // }

                    return style2.CardStyle != style1.CardStyle;

                case ConstData.CardStyle4: //普通炸弹
                    if (style2.CardStyle == ConstData.CardStyle5)
                    {
                        return false;
                    }
                    else if (style2.CardStyle == ConstData.CardStyle4)
                    {
                        return style1.CardValue > style2.CardValue;
                    }

                    return true;
                case ConstData.CardStyle331: //飞机
                case ConstData.CardStyle332:
                    if (style2.CardStyle == style1.CardStyle && style2.CardCnt == style1.CardCnt)
                    {
                        return style1.CardValue > style2.CardValue;
                    }

                    return false;

                case ConstData.CardStyle123: //顺子
                case ConstData.CardStyle112233:
                case ConstData.CardStyle111222:
                    if (style2.CardStyle == style1.CardStyle && style1.CardCnt == style2.CardCnt)
                    {
                        return style1.CardValue > style2.CardValue;
                    }

                    return false;

                //单张 对子 三张 三带1 四带2
                case ConstData.CardStyle1:
                case ConstData.CardStyle2:
                case ConstData.CardStyle3:
                case ConstData.CardStyle31:
                case ConstData.CardStyle32:
                case ConstData.CardStyle41:
                case ConstData.CardStyle42:
                    return style2.CardStyle == style1.CardStyle && style1.CardValue > style2.CardValue;
            }

            return true;
        }


        public static bool operator <(CardStyleInfo style1, CardStyleInfo style2)
        {
            return style2 > style1;
        }
    }
    
    [MessagePackObject]
    public class OperatePack
    {
        /// <summary>
        /// 操作类型
        /// </summary>
        [Key(0)]
        public int OperateType;

        /// <summary>
        /// 操作的牌型
        /// </summary>
        [Key(1)]
        public CardStyleInfo OpCardStyleInfo;

        /// <summary>
        /// 操作之
        /// </summary>
        [Key(2)]
        public int[] Value;

        public void Reset()
        {
            OperateType = -1;
            OpCardStyleInfo = default;
            Value = null;
        }
    }
}