package algorithm

type Cards []byte

// todo 两对和四张起脚牌的判定

var StraightMask = []uint16{15872, 7936, 3968, 1984, 992, 496, 248, 124, 62, 31}

// 顺子（Straight，亦称“蛇”）
// 此牌由五张顺序扑克牌组成。
// 平手牌：如果不止一人抓到此牌，则五张牌中点数最大的赢得此局，
// 如果所有牌点数都相同，平分彩池。
func (c *Cards) straight() uint32 {
	var handvalue uint16
	for _, v := range *c {
		value := v & 0xF
		// 0xE 1110
		if value == 0xE {
			handvalue |= 1
		}
		//0b0011111000000000, // 15872: A-2-3-4-5（特殊顺子，A作为1）  0b0000000000011111, // 31:    10-J-Q-K-A（A作为14）
		handvalue |= (1 << (value - 1))
	}

	for i := uint8(0); i < 10; i++ {
		if handvalue&StraightMask[i] == StraightMask[i] {
			// 10-i+4 代表顺子中最大牌型
			return En(STRAIGHT, uint32(10-i+4))
		}
	}
	return 0
}

// 同花顺（Straight Flush）
// 五张同花色的连续牌。
// 平手牌：如果摊牌时有两副或多副同花顺，连续牌的头张牌大的获得筹码。
// 如果是两副或多副相同的连续牌，平分筹码。
func (c *Cards) straightFlush() uint32 {
	cards := *c
	for i := byte(0); i < SUITSIZE; i++ {
		var handvalue uint16
		for _, v := range cards {
			if (v >> 4) == i {
				value := v & 0xF
				if value == 0xE {
					handvalue |= 1
				}
				handvalue |= (1 << (value - 1))
			}
		}

		for i := uint8(0); i < 10; i++ {
			if handvalue&StraightMask[i] == StraightMask[i] {
				return En(STRAIGHT_FLUSH, uint32(10-i+4))
			}
		}
	}
	return 0
}

// 皇家同花顺（Royal Flush）
// 同花色的A, K, Q, J和10。
// 平手牌：在摊牌的时候有两副多副皇家同花顺时，平分筹码。
func (c *Cards) royalFlush() uint32 {
	cards := *c
	for i := byte(0); i < SUITSIZE; i++ {
		var handvalue uint16
		for _, v := range cards {
			if (v >> 4) == i {
				value := v & 0xF
				if value == 0xE {
					handvalue |= 1
				}
				handvalue |= (1 << (value - 1))

			}
		}

		if handvalue&StraightMask[0] == StraightMask[0] {
			return En(ROYAL_FLUSH, 0)
		}
	}
	return 0
}

// 四条（Four of a Kind，亦称“铁支”、“四张”或“炸弹”）
// 其中四张是相同点数但不同花的扑克牌，第五张是随意的一张牌。
// 平手牌：如果两组或者更多组摊牌，则四张牌中的最大者赢局，如果一组人持有的四张牌是一样的，
// 那么第五张牌最大者赢局（起脚牌,2张起手牌中小的那张就叫做起脚牌）。如果起脚牌也一样，平分彩池。
func (c *Cards) four(counter *ValueCounter) uint32 {
	cards := *c
	if counter.Get(cards[len(cards)-1]) == 4 {
		return En(FOUR, ToValue(cards))
	}
	return 0
}

// 满堂彩（Fullhouse，葫芦，三带二）
// 由三张相同点数及任何两张其他相同点数的扑克牌组成。
// 平手牌：如果两组或者更多组摊牌，那么三张相同点数中较大者赢局。
// 如果三张牌都一样，则两张牌中点数较大者赢局，如果所有的牌都一样，则平分彩池。
func (c *Cards) fullFouse(counter *ValueCounter) uint32 {
	cards := *c
	length := len(cards)

	if length >= 5 {
		if cards[length-1]&0xF == cards[length-2]&0xF &&
			cards[length-3]&0xF == cards[length-1]&0xF &&
			cards[length-4]&0xF == cards[length-5]&0xF {

			return En(FULL_HOUSE, ToValue(cards))
		}
	}
	return 0
}

// 同花（Flush，简称“花”）
// 此牌由五张不按顺序但相同花的扑克牌组成。
// 平手牌：如果不止一人抓到此牌相，则牌点最高的人赢得该局，
// 如果最大点相同，则由第二、第三、第四或者第五张牌来决定胜负，如果所有的牌都相同，平分彩池。
func (c *Cards) flush() uint32 {
	cards := *c
	for i := byte(0); i < SUITSIZE; i++ {
		var count uint8
		for _, v := range cards {
			if (v >> 4) == i {
				count++
			}
		}
		if count >= 5 {
			var handvalue uint16
			fCards := cards[len(cards)-5:]
			for _, v1 := range fCards {
				if (v1 >> 4) == i {
					value := v1 & 0xF
					if value == 0xE {
						handvalue |= 1
					}
					handvalue |= 1 << (value - 1)
				}
			}
			return En(FLUSH, uint32(handvalue))
		}

	}
	return 0
}

// 三条（Three of a kind，亦称“三张”）
// 由三张相同点数和两张不同点数的扑克组成。
// 平手牌：如果不止一人抓到此牌，则三张牌中最大点数者赢局，
// 如果三张牌都相同，比较第四张牌，必要时比较第五张，点数大的人赢局。如果所有牌都相同，则平分彩池。
func (c *Cards) three(counter *ValueCounter) uint32 {
	cards := *c
	if counter.Get(cards[len(cards)-1]) == 3 {
		return En(THREE, ToValue(cards))
	}
	return 0
}

// 两对（Two Pairs）
// 两对点数相同但两两不同的扑克和随意的一张牌组成。
// 平手牌：如果不止一人抓大此牌相，牌点比较大的人赢，如果比较大的牌点相同，那么较小牌点中的较大者赢，
// 如果两对牌点相同，那么第五张牌点较大者赢（起脚牌,2张起手牌中小的那张就叫做起脚牌）。如果起脚牌也相同，则平分彩池。
func (c *Cards) twoPair() uint32 {
	cards := *c
	length := len(cards)
	if length >= 4 {
		if cards[length-1]&0xF == cards[length-2]&0xF &&
			cards[length-3]&0xF == cards[length-4]&0xF {
			return En(TWO_PAIR, ToValue(cards))
		}
	}
	return 0
}

// 一对（One Pair）
// 由两张相同点数的扑克牌和另三张随意的牌组成。
// 平手牌：如果不止一人抓到此牌，则两张牌中点数大的赢，如果对牌都一样，则比较另外三张牌中大的赢，
// 如果另外三张牌中较大的也一样则比较第二大的和第三大的，如果所有的牌都一样，则平分彩池。
func (c *Cards) onePair() uint32 {
	cards := *c
	length := len(cards)
	if length >= 2 {
		if cards[length-1]&0xF == cards[length-2]&0xF {
			return En(ONE_PAIR, ToValue(cards))
		}
	}
	return 0
}

func ToValue(cards []byte) uint32 {
	var res uint32
	for i := len(cards) - 1; i >= 0; i-- {
		res *= 10
		res += uint32(cards[i] & 0xF)
	}
	return res
}

// ToValueHex 如果牌面值可能 ≥10，可以用 16 进制 或 分段编码;16 进制编码（支持 0~15）
func ToValueHex(cards []byte) uint32 {
	var res uint32
	for i := len(cards) - 1; i >= 0; i-- {
		res <<= 4 // 左移 4 位（相当于 *16）
		res |= uint32(cards[i] & 0xF)
	}
	return res
}

// 示例：[0x0A, 0x0B] → 0xAB（171）

func De(v uint32) (uint8, uint32) {
	return uint8(v >> 24), v & 0xFFFFFF
}

// En 高 8 位（bits 24~31） 存储 t（类型）。
// 低 24 位（bits 0~23） 存储 v（数值）
func En(t uint8, v uint32) uint32 {
	v1 := v | (uint32(t) << 24)
	return v1
}
