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

namespace GameMessage.GuanDan
{
    /// <summary>
    /// 扑克花色
    /// </summary>
    [Serializable]
    public enum Suit : int
    {
        /// <summary>
        /// 红桃
        /// </summary>
        Heart = 1,

        /// <summary>
        /// 方块
        /// </summary>
        Diamond = 2,

        /// <summary>
        /// 黑桃
        /// </summary>
        Spade = 3,

        /// <summary>
        /// 梅花
        /// </summary>
        Club = 4,

        /// <summary>
        /// 王
        /// </summary>
        Joker = 5,
    }
    
    /// <summary>
    /// 掼蛋收发包
    /// </summary>
    [MessagePackObject]
    public class GDPack
    {
        /// <summary>
        /// 游戏阶段
        /// </summary>
        [Key(0)] public int Stage;

        /// <summary>
        /// 当前游戏倍数，暂时未有加倍
        /// </summary>
        [Key(1)] public int CurrentMultiple;

        /// <summary>
        /// 玩家加倍情况 
        /// </summary>
        [Key(2)] public int[] MultipleInfo;

        /// <summary>
        /// 自身位置,只有初始化手牌的时候有用
        /// </summary>
        [Key(3)] public int SelfPos;

        /// <summary>
        /// 接风的位置
        /// </summary>
        [Key(4)] public int WindPos;

        /// <summary>
        /// 当前等级
        /// </summary>
        [Key(5)] public int CurRank;

        /// <summary>
        /// 上家行动位置
        /// </summary>
        [Key(6)] public int PrePos;

        /// <summary>
        /// 当前行动位置
        /// </summary>
        [Key(7)] public int CurPos;


        /// <summary>
        /// 当前出牌信息
        /// </summary>
        [Key(8)] public CardInfo CurAction;

        /// <summary>
        /// 最大出牌人的位置
        /// </summary>
        [Key(9)] public int GreaterPos;

        /// <summary>
        /// 最大出牌的信息
        /// </summary>
        [Key(10)] public CardInfo GreaterAction;

        /// <summary>
        /// 手牌
        /// </summary>
        [Key(11)] public List<GDCard> HandCards;

        /// <summary>
        /// 所有人出牌消息
        /// </summary>
        [Key(12)] public PublicInfo[] AllOutCardInfo;

        /// <summary>
        /// 所有可出牌的列表，客户端为空，仅由服务器使用
        /// </summary>
        [Key(13)] public CardInfo[] ActionList;

        /// <summary>
        /// 可选动作范围 (包含0和IndexRange)客户端为空，仅由服务器使用
        /// </summary>
        [Key(14)] public int IndexRange;

        /// <summary>
        /// 结算信息
        /// </summary>
        [Key(15)] public Settlement[] OverInfo;

        /// <summary>
        /// 玩家托管状态,1是托管，2是正常
        /// </summary>
        [Key(16)] public int[] PlayerDeposit;

        /// <summary>
        /// 进贡关系
        /// </summary>
        [Key(17)] public Dictionary<int, int> TributeShip;

        /// <summary>
        /// 还贡关系
        /// </summary>
        [Key(18)] public Dictionary<int, int> BackShip;

        /// <summary>
        /// 所有人的积分或等级
        /// </summary>
        [Key(19)] public List<int> AllScore;

        [Key(20)]
        public int idx;
        
        public GDPack()
        {
            PlayerDeposit = new int[4] { 2, 2, 2, 2 };
            OverInfo = new Settlement[4];
            ActionList = null;
            AllOutCardInfo = new PublicInfo[4]
                { new PublicInfo(), new PublicInfo(), new PublicInfo(), new PublicInfo() };
            HandCards = new List<GDCard>();
            MultipleInfo = new int[4] { 0, 0, 0, 0 };
            CurAction = new CardInfo();
            GreaterAction = new CardInfo();
            WindPos = -1;
            TributeShip = new Dictionary<int, int>();
            BackShip = new Dictionary<int, int>();
            AllScore = new List<int>();
        }

        public GDPack Copy()
        {
            GDPack newPack = new GDPack();
            newPack.PlayerDeposit = PlayerDeposit;
            newPack.OverInfo = OverInfo;
            newPack.AllOutCardInfo = AllOutCardInfo;
            newPack.HandCards = HandCards;
            newPack.MultipleInfo = MultipleInfo;
            newPack.CurAction = CurAction;
            newPack.CurPos = CurPos;
            newPack.PrePos = PrePos;
            newPack.CurRank = CurRank;
            newPack.GreaterPos = GreaterPos;
            newPack.Stage = Stage;
            newPack.IndexRange = IndexRange;
            newPack.SelfPos = SelfPos;
            newPack.GreaterAction = GreaterAction;
            newPack.WindPos = WindPos;
            newPack.BackShip = BackShip;
            newPack.AllScore = AllScore;
            newPack.TributeShip = TributeShip;
            newPack.ActionList = ActionList;
            return newPack;
        }
    }

    /// <summary>
    /// 公共消息
    /// </summary>
    [MessagePackObject]
    public class PublicInfo
    {
        /// <summary>
        /// 用来存储特定信息，具体阶段具体分析,进贡还贡阶段用来存储是进贡还是抗贡,1进贡，2等待进贡，3抗贡，4还贡，5等待还贡
        /// 打牌阶段用来存储手牌的数量
        /// 如果是负数，则代表已经打完了牌，绝对值代表排名-1头游，-2二游，-3三游，-4下游
        /// </summary>
        [Key(0)] public int Rest;

        /// <summary>
        /// 牌型信息
        /// </summary>
        [Key(1)] public CardInfo PlayArea;
        
        public PublicInfo()
        {
            PlayArea = new CardInfo();
        }
    }

    /// <summary>
    /// 牌型信息
    /// </summary>
    [MessagePackObject]
    public class CardInfo
    {
        /// <summary>
        /// 牌型
        /// </summary>
        [Key(0)] public int Style;

        /// <summary>
        /// 点数
        /// </summary>
        [Key(1)] public int Point;

        /// <summary>
        /// 出牌
        /// </summary>
        [Key(2)] public List<GDCard> OutCard;

        public CardInfo()
        {
            OutCard = new List<GDCard>();
        }

        public static CardInfo Create(int style, int point, List<GDCard> cards)
        {
            return new CardInfo()
            {
                Style = style,
                Point = point,
                OutCard = cards
            };
        }
        
        public override string ToString()
        {
            string str = String.Empty;
            if (OutCard == null || OutCard.Count == 0)
            {
                return "过";
            }

            for (int i = 0; i < OutCard.Count; i++)
            {
                str += OutCard[i].ToString() + "  ";
            }

            return str;
        }
    }

    /// <summary>
    /// 结算信息
    /// </summary>
    [MessagePackObject]
    public class Settlement
    {
        /// <summary>
        /// 位置
        /// </summary>
        [Key(0)] public int Pos;

        /// <summary>
        /// 总输赢，多少个子
        /// </summary>
        [Key(1)] public int TotalNum;
    }

    /// <summary>
    /// 进贡状态
    /// </summary>
    public enum TributeState : int
    {
        Tribute = 1, //需进贡
        WaitTribute = 2, //等待进贡
        AniTribute = 3, //抗贡
        Back = 4, //需还贡
        WaitBack = 5, //等待还贡
    }

    [Serializable]
    [MessagePackObject]
    public class GDCard
    {
        /// <summary>
        /// Id 是从1开始到54
        /// </summary>
        [Key(0)] public int Id;

        [Key(1)] public Suit Flower;

        /// <summary>
        /// 15 小王 - 16 大王
        /// </summary>
        [Key(2)] public int Num;

        public GDCard()
        {
        }

        public static GDCard Create(int id, int num, Suit flower)
        {
            return new GDCard()
            {
                Id = id,
                Num = num,
                Flower = flower
            };
        }
        
        public static GDCard Create(int num, Suit flower)
        {
            GDCard self = new GDCard();
            self.Flower = flower;
            self.Num = num;
            if (num == 15)
                self.Id = 53;
            else if (num == 16)
                self.Id = 54;
            else
            {
                self.Id = ((int)(flower - 1) * 13 + (self.Num - 1));
            }

            return self;
        }

        public override string ToString()
        {
            var suitStr = string.Empty;
            switch (Flower)
            {
                case Suit.Spade:
                    suitStr = "黑桃";
                    break;
                case Suit.Heart:
                    suitStr = "红心";
                    break;
                case Suit.Club:
                    suitStr = "梅花";
                    break;
                case Suit.Diamond:
                    suitStr = "方块";
                    break;
                case Suit.Joker:
                    return (Num == 15 ? "小王" : "大王");
                default:
                    throw new ArgumentOutOfRangeException(nameof(Flower));
            }

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

            return Id + suitStr + valueStr;
        }
    }
}