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

namespace GameMessage.SRDaZha
{
    [MessagePackObject]
    public struct DaZhaCardPack
    {
        /// <summary>
        /// 4个玩家手牌
        /// </summary>
        [Key(0)]
        public PlayCard[] PlayCard;
        public void Init()
        {
            PlayCard = new PlayCard[4];
        }
    }

    [MessagePackObject]
    public struct DaZhaLogicInfo
    {
        /// <summary>
        /// 游戏流程 1游戏开始 2游戏发牌 3抢叫 4叫牌 5打牌 6结算
        /// </summary>
        [Key(0)]
        public byte GameZT;
        /// <summary>
        /// 最大的出牌内容
        /// </summary>
        [Key(1)]
        public PlayOutCard MaxPlayCard;
        /// <summary>
        /// 当前出牌内容
        /// </summary>
        [Key(2)]
        public PlayOutCard ActivePlayCard;

        /// <summary>
        /// 控制权是哪个位置1-4
        /// </summary>
        [Key(3)]
        public byte WhoPlay;

        /// <summary>
        /// 庄的位置1-4
        /// </summary>
        [Key(4)]
        public byte ZhuangPos;

        /// <summary>
        /// 本轮分数
        /// </summary>
        [Key(5)]
        public byte LunFen;

        /// <summary>
        /// 是否有废王
        /// </summary>
        [Key(6)]
        public bool IsHaveFeiWang;

        /// <summary>
        /// 存储4个玩家抢叫的值 1是抢叫 2不抢叫
        /// </summary>
        [Key(7)]
        public byte[] QiangJiaoPos;

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

        /// <summary>
        /// 谁和谁是队友,暗叫的话等叫的牌打出来了再赋值进去
        /// 如果玩家是一打三，那第一个位置就是玩家自己的位置。第二个位置就是100（没有这个位置所以就表示他没有队友，就是一打三）
        /// 100以后就是暗叫的队友等牌打出以后再减去100赋值真正的队友值进去
        /// </summary>
        [Key(9)]
        public byte[] DuiYouPos;

        /// <summary>
        /// 玩家捡分
        /// </summary>
        [Key(10)]
        public byte[] JianFen;

        /// <summary>
        /// 奖分-玩家炸弹分
        /// </summary>
        [Key(11)]
        public short[] JiangFen;

        /// <summary>
        /// 罚分
        /// </summary>
        [Key(12)]
        public short[] FaFen;
        /// <summary>
        /// 输赢分
        /// </summary>
        [Key(13)]
        public short[] ShuYingFen;

        /// <summary>
        /// 存储废王的牌
        /// </summary>
        [Key(14)]
        public PlayOutCard[] FeiWangCards;

        /// <summary>
        /// 记录炸弹牌型，结算显示。可能打牌过程中会回添加，结算也会添加
        /// </summary>
        [Key(15)]
        public List<PlayOutCard> ZhaDanPaiXing;

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

        /// <summary>
        /// 是否是最后一局
        /// </summary>
        [Key(17)]
        public bool IsLast;

        public void Init()
        {
            MaxPlayCard = new PlayOutCard();
            ActivePlayCard = new PlayOutCard();
            LunFen = 0;
            JianFen = new byte[4];
            JiangFen = new short[4];
            FaFen = new short[4];
            ShuYingFen = new short[4];
            OverPos = new byte[4];
            JiaoCard = new byte[2];
            QiangJiaoPos = new byte[4];
            DuiYouPos = new byte[2];
            ZhaDanPaiXing = null;
            ZhaDanPaiXing = new List<PlayOutCard>();
            this.IsHaveFeiWang = false;
            this.IsLast = false;
        }
    }

    [MessagePackObject]
    public struct DaZhaGamePack
    {
        /// <summary>
        /// 牌的内存包
        /// </summary>
        [Key(0)]
        public DaZhaCardPack CardPack;
        /// <summary>
        /// 逻辑内存包
        /// </summary>
        [Key(1)]
        public DaZhaLogicInfo LogicInfo;

        /// <summary>
        /// 玩法规则
        /// </summary>
        [Key(2)]
        public FriendGuiZe WanFaGuiZe;

        public void Init()
        {
            CardPack.Init();
            LogicInfo.Init();
            WanFaGuiZe.Init();
        }
    }

    /// <summary>
    /// 朋友房规则-0值无效，初始化的状态
    /// </summary>
    [MessagePackObject]
    public struct FriendGuiZe
    {
        /// <summary>
        /// 是否是朋友房 2不是朋友房 1是朋友房
        /// </summary>
        [Key(0)]
        public byte IsFriend;
        /// <summary>
        /// 是否明叫 1是（是明叫模式，叫完牌以后会立马显示分边情况，谁和谁是队友） 
        /// 2不是（暗叫是当叫牌打出以后才会显示分边情况）
        /// </summary>
        [Key(1)]
        public byte MingJiao;

        /// <summary>
        /// 是否抢叫 2不是 1是（从庄家开始，每一家都可以选择一打三或者不打，当所有玩家都不打时，庄家再进行一次叫牌，这次叫牌不能叫自己）  
        /// </summary>
        [Key(2)]
        public byte QiangJiao;

        /// <summary>
        /// 2不捡分 1是捡分
        /// </summary>
        [Key(3)]
        public byte JianFen;

        /// <summary>
        /// 2不可顺子 1可以出顺子
        /// </summary>
        [Key(4)]
        public byte ShunZi;

        /// <summary>
        /// 2不可三带二（就只能出3张） 1可以三带二（必须带牌除非牌不够）
        /// </summary>
        [Key(5)]
        public byte SanDai2;

        /// <summary>
        /// 2不可连队 1可以连队
        /// </summary>
        [Key(6)]
        public byte LianDui;

        /// <summary>
        /// 2废王不罚分 1废王罚分
        /// </summary>
        [Key(7)]
        public byte FeiWangScore;

        /// <summary>
        /// 2废王不显示 1废王显示
        /// </summary>
        [Key(8)]
        public byte FeiWangVisible;

        /// <summary>
        /// 2不内销 1内销(内销就是不打的炸也算分，只有在1打3的情况下才有内销。1打3 的情况下，如果是叫牌玩家获胜，其余玩家手牌里的炸弹各自结算，与叫牌玩家无关)
        /// </summary>
        [Key(9)]
        public byte NeiXiao;

        /// <summary>
        /// 2不八王（不八王就是4个王，完整的2副牌） 1八王（2副牌的基础上再加2对大小王）
        /// </summary>
        [Key(10)]
        public byte BaWang;

        /// <summary>
        /// 2不是炸弹玩法 1是炸弹玩法
        /// </summary>
        [Key(11)]
        public byte ZhaDang;

        /// <summary>
        /// 2不可5-10k 1可以5-10k
        /// </summary>
        [Key(12)]
        public byte WuShiK;

        /// <summary>
        /// 2不是200分 1是200分（如果要玩200分模式一定得勾选捡分模式）
        /// </summary>
        [Key(13)]
        public byte LiangBaiFen;

        /// <summary>
        /// 2不是硬八炸 1是硬八炸（8个一样的牌型炸弹奖励翻倍，也就是当成9个头算分）
        /// </summary>
        [Key(14)]
        public byte YingBaZha;

        /// <summary>
        /// 2不是废王摊牌 1是废王摊牌(发完牌以后，这把有废王的话就摊牌，直接结算。直接算炸弹分和罚王分。这个时候就属于是内销模式)
        /// </summary>
        [Key(15)]
        public byte FeiWangTanPai;

        /// <summary>
        /// 2不是13王玩法 1是13王玩法(13王玩法，要勾选510K不为炸弹、是明叫、不是八王。规则是：1-K每种类型的牌是7张，王13张。一共104张牌。每人26张牌。)
        /// </summary>
        [Key(16)]
        public byte ShiSanWangWanFa;

        /// <summary>
        /// 2随机发 1每次发3张牌
        /// </summary>
        [Key(17)]
        public byte FaSanZhang;

        /// <summary>
        /// 最后一局解散 1是 2不是
        /// </summary>
        [Key(18)]
        public byte IsLastDisband;

        public void Init()
        {
            MingJiao = 0;
            QiangJiao = 0;
            JianFen = 0;
            ShunZi = 0;
            SanDai2 = 0;
            LianDui = 0;
            FeiWangScore = 0;
            FeiWangVisible = 0;
            NeiXiao = 0;
            BaWang = 0;
            ZhaDang = 0;
            WuShiK = 0;
            LiangBaiFen = 0;
            YingBaZha = 0;
            FeiWangTanPai = 0;
            ShiSanWangWanFa = 0;
            FaSanZhang = 0;
        }
        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            if (MingJiao > 0)
                sb.Append((MingJiao == 1 ? "明叫 " : "暗叫 "));
            if (QiangJiao > 0)
                sb.Append((QiangJiao == 1 ? "抢叫 " : "不可抢叫 "));
            if (JianFen > 0)
                sb.Append((JianFen == 1 ? "捡分 " : "不捡分 "));
            if (ShunZi > 0)
                sb.Append((ShunZi == 1 ? "可顺子 " : "不可顺子 "));
            if (SanDai2 > 0)
                sb.Append((SanDai2 == 1 ? "可三带二 " : "不可三带二 "));
            if (LianDui > 0)
                sb.Append((LianDui == 1 ? "可连对 " : "不可连对 "));
            if (FeiWangScore > 0)
                sb.Append((FeiWangScore == 1 ? "废王罚分 " : "废王不罚分 "));
            if (FeiWangVisible > 0)
                sb.Append((FeiWangVisible == 1 ? "废王显示 " : "废王不显示 "));
            if (NeiXiao > 0)
                sb.Append((NeiXiao == 1 ? "内销 " : "不内销 "));
            if (BaWang > 0 && ShiSanWangWanFa != 1)
                sb.Append((BaWang == 1 ? "八王 " : "4王 "));
            sb.Append((ZhaDang == 1 ? "炸弹玩法 " : ""));
            if (WuShiK > 0)
                sb.Append((WuShiK == 1 ? "510K为炸弹 " : "510K不是炸弹 "));
            if (LiangBaiFen > 0)
                sb.Append((LiangBaiFen == 1 ? "200分玩法 " : ""));
            if (YingBaZha > 0)
                sb.Append((YingBaZha == 1 ? "硬八炸 " : ""));
            if (FeiWangTanPai > 0)
                sb.Append((FeiWangTanPai == 1 ? "废王摊牌 " : ""));
            if (ShiSanWangWanFa > 0)
                sb.Append((ShiSanWangWanFa == 1 ? "13王玩法 " : ""));
            if (IsLastDisband > 0)
                sb.Append((IsLastDisband == 1 ? "最后一局解散 " : ""));
            return sb.ToString();
        }
    }

    [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 PlayOutCard : IPlayOutCardType1
    {
        /// <summary>
        /// 牌的位置从1开始
        /// </summary>
        [Key(0)]
        public byte Pos { get; set; }

        /// <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 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;

        /// <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;
        }
    }
}
