package samloc

import (
	"sort"
)

const (
	Pass               int = iota //0 nil
	Single                        //1 单张
	Twin                          //2 对子
	Triple                        //3 三张
	Straight                      //4 顺子
	Four                          //5 四张
	TwinFour                      //6 两组四张
	StraightFiveTriple            //7 五连对
	ThreeTriple                   //8 三个三张
	ColorSame                     //9 同色
	Four2                         //10 四张二
	TenStraight                   //11 一条龙
)

const (
	POKER_3  int32 = iota // 0
	POKER_4               // 1
	POKER_5               // 2
	POKER_6               // 3
	POKER_7               // 4
	POKER_8               // 5
	POKER_9               // 6
	POKER_10              // 7
	POKER_J               // 8
	POKER_Q               // 9
	POKER_K               // 10
	POKER_A               // 11
	POKER_2               // 12
)

const (
	Club    int = iota //0,黑桃
	Spade              //1,梅花
	Diamond            //2,方块
	Heart              //3,红桃
)

const (
	Score2      int32 = 15 //4张 压2
	ScoreFour   int32 = 20 //4张 压4张
	ScoreBaoSam int32 = 20 //baosam
	ScoreLore   int32 = 20 // 通杀
	Baopei2     int32 = 10 // 包赔
	Treo        int32 = 15 // 结束游戏后而不打出任何牌
)

const (
	BaosamNot  int = 1 //  0 非baosam 正常结算
	BaosamWin  int = 2 //  1 baosam赢
	BaosamLose int = 4 //  2 baosam输
	SamLore    int = 8 //  2 通杀
)

// KindOfCard 牌型
type KindOfCard struct {
	kind int //牌型
	// cards []int32 //出牌
	min   int32 //最小牌
	max   int32 //最大牌
	len   int32 //牌的长度
	same  int32 //同牌数量 33 -> 2
	num   int32 //牌的数量
	ktype int   //牌的权重
}

func (this *KindOfCard) GetKind() int   { return this.kind }
func (this *KindOfCard) GetLen() int32  { return this.len }
func (this *KindOfCard) GetMin() int32  { return this.min }
func (this *KindOfCard) GetSame() int32 { return this.same }
func (this *KindOfCard) GetNum() int32  { return this.num }

type Kds struct {
	kd []*KindOfCard
}

func (this *Kds) Len() int      { return len(this.kd) }
func (this *Kds) Swap(i, j int) { this.kd[i], this.kd[j] = this.kd[j], this.kd[i] }
func (this *Kds) Less(i, j int) bool {
	if this.kd[i].ktype > this.kd[j].ktype { // 大到小
		return true
	} else if this.kd[i].ktype < this.kd[j].ktype {
		return false
	}
	if this.kd[i].len > this.kd[j].len {
		return true
	}
	if this.kd[i].min < this.kd[j].min {
		if this.kd[i].min < 0 { // A 2做连 往后放
			return false
		}
		return true
	}
	return false // 小到大
}

//func (this *KindOfCard) GetCards() []int32 { return this.cards }
func (this *KindOfCard) OutPokers(poker []int32) []int32 {
	pok := make([]int32, len(poker))
	copy(pok, poker)
	var ret []int32
	if this != nil && this.num != 0 {

		for i := this.min; i <= this.max; {
			va := i
			if va < 0 {
				va = va + POKER_2 + 1
			}
			for j := 0; j != int(this.same); j++ {
				for k, v := range pok {
					if Value32(v) == va {
						ret = append(ret, v)
						pok = append(pok[:k], pok[k+1:]...) // del
						break
					}
				}
			}
			if this.same > 3 && i != this.max {
				i = this.max
			} else {
				i++
			}
		}

	}

	return ret
}

// SortInt32 []int32
type SortInt32 []int32

func (a SortInt32) Len() int      { return len(a) }
func (a SortInt32) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a SortInt32) Less(i, j int) bool {

	b := Value(a[i])
	c := Value(a[j])

	if b == c {
		return b < c
	}
	return b < c
}

// Color 黑桃0 梅花1 方片2 紅桃3
func Color(c int32) int {
	return int(c) / PER_CARD_COLOR_MAX
}

func RedColor(c int32) int { // Heart 红色 Club 黑色
	if (int(c) / PER_CARD_COLOR_MAX) > Spade {
		return Heart
	}
	return Club
}

func Value(c int32) int {
	return int(c) % PER_CARD_COLOR_MAX
}

func Value32(c int32) int32 {
	return c % PER_CARD_COLOR_MAX
}

func ValueStr(c int32) int {
	if int(c+3)%PER_CARD_COLOR_MAX == 0 {
		return PER_CARD_COLOR_MAX
	}
	return int(c+3) % PER_CARD_COLOR_MAX
}

func IsSingle(cards []int32) bool { //单张
	if len(cards) == 1 {
		return true
	}
	return false
}

func IsContainPOKER2(cards []int32) bool { //全是2
	for _, v := range cards {
		if Value32(v) == POKER_2 {
			return true
		}
	}
	return false
}

func IsHavePOKER2(cards []int32) bool { //全是2
	for _, v := range cards {
		if v == InvalideCard {
			continue
		}
		if Value32(v) != POKER_2 {
			return false
		}
	}
	return true
}

func DelOtherPOKER2(cards []int32, del []int32) bool { //全是2
	cpcards := append([]int32{}, cards...)
	for _, v := range del {
		for i, k := range cpcards {
			if v == k {
				cpcards[i] = InvalideCard
			}
		}
	}
	num := 0
	for _, v := range cpcards {
		if v == InvalideCard {
			num++
			continue
		}
		if Value32(v) != POKER_2 {
			return false
		}
	}
	if num == Hand_CardNum {
		return false
	}
	return true
}

func GetMaxCard(cards []int32) int32 { //单张
	max := int32(0)
	for _, v := range cards {
		if v != InvalideCard {
			vv := Value32(v)
			if vv > max {
				max = vv
			}
		}
	}
	return max
}

func IsTwin(cards []int32) bool { //对子
	if len(cards) == 2 {
		if Value(cards[0]) == Value(cards[1]) {
			return true
		}
	}
	return false
}

func IsValueStraight(tmpCards []int32) bool { //顺子
	if IsContainPOKER2(tmpCards) { // 包含2 单连要

		for i := range tmpCards {
			if tmpCards[i] > POKER_K {
				tmpCards[i] = tmpCards[i] - POKER_2 - 1
			}
		}
		sort.Sort(SortInt32(tmpCards))
	}
	if len(tmpCards) < 3 || len(tmpCards) > 12 {
		return false
	}

	for i := 0; i < len(tmpCards)-1; i++ {
		card := tmpCards[i]
		nextCard := tmpCards[i+1]
		if nextCard-card != 1 { // 不相邻
			return false
		}
	}

	return true
}

func IsTriple(cards []int32) bool { //三张
	if len(cards)%3 != 0 {
		return false
	}
	if Value(cards[0]) != Value(cards[1]) {
		return false
	}
	if Value(cards[1]) != Value(cards[2]) {
		return false
	}
	return true
}

func IsFour(cards []int32) bool { //四张
	if len(cards) != 4 {
		return false
	}
	if Value(cards[0]) != Value(cards[1]) {
		return false
	}
	if Value(cards[1]) != Value(cards[2]) {
		return false
	}
	if Value(cards[2]) != Value(cards[3]) {
		return false
	}
	return true
}

func IsDouFour(cards []int32) bool { //两 四张
	if len(cards) != 8 {
		return false
	}
	tmpCards := []int32{}
	for _, card := range cards {

		tmpCards = append(tmpCards, int32(Value(card)))
	}
	sort.Sort(SortInt32(tmpCards))
	// fmt.Println(tmpCards[:4], tmpCards[4:], IsFour(tmpCards[:4]), IsFour(tmpCards[4:]))
	if IsFour(tmpCards[:4]) && IsFour(tmpCards[4:]) {
		return true
	}
	return false
}

func IsColorSame(cards []int32) bool { // 同色

	c := RedColor(cards[0])
	for _, card := range cards {
		if c != RedColor(card) {
			return false
		}
	}
	return true
}

func pt32m(cards []int32) map[int32]int32 {
	m := make(map[int32]int32)
	for _, v := range cards {
		m[Value32(v)]++
	}
	return m
}

func ptstr32m(cards []int32) map[int32]int32 {
	m := make(map[int32]int32)
	for _, v := range cards {
		vl := Value32(v)
		m[vl]++
	}
	if m[POKER_2] != 0 {
		m[POKER_2-POKER_2-1] = m[POKER_2]
		m[POKER_A-POKER_2-1] = m[POKER_A]
	}
	return m
}

/*func findcardCommon(m map[int]int32, n int32) (res [][]int32) {
	max := int(POKER_2)

	for i := 0; i <= max; i++ {
		if m[i] >= n {
			res = append(res, []int32{}...)
		}
	}
	return
}*/

// 通杀
func CardLore(cards []int32) (int, int32) {

	if int32(len(cards)) != HandCardNum {
		return Pass, -3
	}
	for _, v := range cards {
		if v == -1 {
			return Pass, -3
		}
	}
	max := POKER_2
	smap := pt32m(cards)

	tmpCards := []int32{}
	for _, card := range cards {

		tmpCards = append(tmpCards, int32(Value(card)))
	}
	sort.Sort(SortInt32(tmpCards))

	// 一条龙>四张2>10张颜色相同>三个三张>五连对

	if IsValueStraight(tmpCards) { // 一条龙
		return TenStraight, tmpCards[HandCardNum-1]
	}

	if smap[POKER_2] == 4 { // 四张
		return Four2, tmpCards[HandCardNum-1]
	}

	if IsColorSame(cards) { // 同色
		return ColorSame, tmpCards[HandCardNum-1]
	}

	threenum := 0
	for i := int32(0); i <= max; i++ {
		v, _ := smap[i]
		if v > 2 {
			threenum++
		}
		if threenum == 3 {
			return ThreeTriple, int32(i)
		}

	}
	freenum := 0
	for i := int32(0); i <= max; i++ {
		v, _ := smap[i]
		if v == 0 && freenum == 0 {
			continue
		}
		if v != 2 {
			return Pass, -3
		}
		if i == POKER_2 {
			return Pass, -3
		}
		freenum += 1
		if freenum == 5 {
			return StraightFiveTriple, int32(i)
		}

	}

	return Pass, -3
}

func GetCardKind(cards []int32) *KindOfCard { // cardType 类型 // 最小

	count := int32(len(cards))
	ret := &KindOfCard{
		num:  count,
		kind: Pass,
		//cards: append([]int32{}, cards...),
	}
	if count <= 0 {
		return ret
	}
	tmpCards := []int32{}
	for _, card := range cards {

		tmpCards = append(tmpCards, int32(Value(card)))
	}
	sort.Sort(SortInt32(tmpCards))

	// fmt.Printf("GetCardKind %x %x\n", cards, tmpCards)
	switch count {
	case 1: //单牌
		ret.min = tmpCards[0]
		ret.max = tmpCards[0]
		ret.len = 1
		ret.same = 1
		ret.kind = Single
		ret.ktype = GetCardType(ret)
		return ret
	case 2: //对牌
		if IsTwin(cards) {
			ret.min = tmpCards[0]
			ret.max = tmpCards[0]
			ret.kind = Twin
			ret.len = 1
			ret.same = 2
			ret.ktype = GetCardType(ret)
		}
		return ret
	}

	return analysCardKind(cards, tmpCards, ret, count)
}

func analysCardKind(cards []int32, tmpCards []int32, ret *KindOfCard, count int32) *KindOfCard { // cardType 类型 // 最小

	switch count {
	case 3:
		if (tmpCards[0] == tmpCards[1]) && IsTriple(tmpCards) {
			ret.min = tmpCards[0]
			ret.max = tmpCards[0]
			ret.kind = Triple
			ret.len = 1
			ret.same = 3
			ret.ktype = GetCardType(ret)
			return ret // 三张
		}
	case 4:
		if (tmpCards[0] == tmpCards[1]) && IsFour(tmpCards) {
			ret.min = tmpCards[0]
			ret.max = tmpCards[0]
			ret.kind = Four
			ret.len = 1
			ret.same = 4
			ret.ktype = GetCardType(ret)
			return ret // 四张
		}
	case 8:
		if (tmpCards[0] == tmpCards[1]) && IsDouFour(tmpCards) {
			ret.min = tmpCards[0]
			ret.max = tmpCards[7]
			ret.kind = TwinFour
			ret.len = 2
			ret.same = 4
			ret.ktype = GetCardType(ret)
			return ret //6 两组四张
		}
	}

	if IsValueStraight(tmpCards) {
		ret.min = tmpCards[0]
		ret.max = tmpCards[len(tmpCards)-1]
		ret.kind = Straight
		ret.len = int32(len(tmpCards))
		ret.same = 1
		ret.ktype = GetCardType(ret)
		return ret // 顺子
	}
	return ret
}

// 首出提示
func HeadHintOut(card []int32) [][]int32 { // 按照单 双 三张 四张 顺子 双四出~

	return nil
}

// 压牌
func PressOut(beforeKind *KindOfCard, cards []int32, f bool) (retkind *KindOfCard) {
	p := pt32m(cards)
	var kds []*KindOfCard
	switch beforeKind.kind {
	case Single: //1 单张
		retkind = GetSingle(cards, beforeKind, f)
		if beforeKind.min == POKER_2 {
			kds = findKindCommon(p, 4)
			for _, kd := range kds {
				if CompareCardKind(beforeKind, kd) {
					retkind = kd
					break
				}
			}
		}
	case Twin: //2 对子
		kds = findKindCommon(p, 2)
		if beforeKind.min == POKER_2 {
			kds = findKindTwinFour(p, 4)
		}
		for _, kd := range kds {
			if CompareCardKind(beforeKind, kd) {
				retkind = kd
				break
			}
		}
	case Straight: //4 顺子
		kds := findStraight(p, 1, beforeKind.num)
		for _, kd := range kds {
			if CompareCardKind(beforeKind, kd) {
				retkind = kd
				break
			}
		}
	case Triple: //3 三张
		kds := findKindCommon(p, 3)
		for _, kd := range kds {
			if CompareCardKind(beforeKind, kd) {
				retkind = kd
				break
			}
		}
	case Four: //5 四张
		kds := findKindCommon(p, 4)
		for _, kd := range kds {
			if CompareCardKind(beforeKind, kd) {
				retkind = kd
				break
			}
		}
	case TwinFour: //6 两组四张
	}
	return
}

// CompareCardKind 对比
func CompareCardKind(beforeKind *KindOfCard, kind *KindOfCard) bool {

	if beforeKind.kind == kind.kind && beforeKind.num == kind.num && beforeKind.kind != TwinFour {

		return beforeKind.min < kind.min
	}

	if beforeKind.min == POKER_2 {
		if beforeKind.kind == Single && kind.kind == Four {
			return true
		} else if beforeKind.kind == Twin && kind.kind == TwinFour {
			return true
		}
	}

	return false
}

// CompareCard 对比
func CompareCard(beforeKind *KindOfCard, cards []int32) bool { // cards 大 返回true
	cnum := int32(len(cards))
	tmpCards := []int32{}
	for _, card := range cards {

		tmpCards = append(tmpCards, int32(Value(card)))
	}
	sort.Sort(SortInt32(tmpCards))
	switch beforeKind.kind {
	case Single: //1 单张
		if cnum == 1 {
			if beforeKind.min < tmpCards[0] {
				return true
			}
		} else if beforeKind.min == POKER_2 && IsFour(tmpCards) { // 能压一个2
			return true
		}

	case Twin: //2 对子
		if cnum == 2 {
			if IsTwin(tmpCards) && beforeKind.min < tmpCards[0] {
				return true
			}
		} else if beforeKind.min == POKER_2 && IsDouFour(tmpCards) { // 能压一对2
			return true
		}
	case Straight: //4 顺子
		//fmt.Println("IsValueStraight(tmpCards)", IsValueStraight(tmpCards), beforeKind.len, cnum, beforeKind.min, tmpCards[0])
		if beforeKind.len == cnum && IsValueStraight(tmpCards) && (beforeKind.min < tmpCards[0]) {
			return true
		}
	case Triple: //3 三张
		if IsTriple(tmpCards) && (beforeKind.min < tmpCards[0]) {
			return true
		}
	case Four: //5 四张
		if IsFour(tmpCards) && (beforeKind.min < tmpCards[0]) {
			return true
		}
	case TwinFour: //6 两组四张
	}
	return false
}

// RemoveCard 删除扑克
func RemoveCard(removePoker []int32, cardData *[]int32) bool {

	deleteCount := 0
	removeCount := len(removePoker)
	pokerCount := len(*cardData)
	tempPokerData := make([]int32, pokerCount)
	if pokerCount > len(tempPokerData) {
		return false
	}

	copy(tempPokerData[0:], (*cardData)[0:pokerCount])

	for i := 0; i < removeCount; i++ {
		for j := 0; j < pokerCount; j++ {
			if removePoker[i] == tempPokerData[j] {
				deleteCount++
				// fmt.Printf("找到待删除扑克： %x\n", removePoker[i])
				tempPokerData[j] = -1
				break
			}
		}
	}
	if deleteCount != removeCount {
		return false
	}

	//清理扑克
	pos := 0
	for i := 0; i < pokerCount; i++ {
		if tempPokerData[i] != -1 {
			(*cardData)[pos] = tempPokerData[i]
			pos++
		}
	}
	(*cardData) = (*cardData)[:pos] // 删除扑克 1244 delete 2 --> 144
	return true
}

func GetCardType(kind *KindOfCard) int {
	switch kind.same {
	case 4:
		// 四张
		if kind.num != 8 {
			// 双四张
			return -1 // 不能首出
		}
		if kind.min > POKER_10 {
			return 1
		}
		return 6
	case 3:
		// 三牌
		if kind.min > POKER_10 {
			return 1
		}
		return 4
	case 2:
		// 对牌
		return 3
	case 1:

		if kind.num >= 3 {
			// 单连
			if kind.num > 5 {
				return 8
			}
			if kind.min < POKER_7 && kind.min >= POKER_3 {
				return 7
			}
			if kind.num == 3 && kind.min > POKER_10 { // 不先出
				return 1
			}
			return 5
		}
	}
	// 单牌
	return 2
}

func MaxSingle(cpCards []int32, delCards []int32, f bool) (ret bool, retCards []int32) {
	if DelOtherPOKER2(cpCards, delCards) || (f && len(delCards) == 1) {
		for i := len(cpCards) - 1; i >= 0; i-- {
			card := cpCards[i]
			if card != InvalideCard {
				retCards = append(retCards, card)
				ret = true
				break
			}
		}
	}
	return
}

func GetSingle(cpCards []int32, kind *KindOfCard, f bool) (retkind *KindOfCard) {
	var retCards []int32
	if kind == nil || kind.num == 0 {
		for _, card := range cpCards {
			if card != InvalideCard {
				retCards = append(retCards, card)
				break
			}
		}
		if ret, del := MaxSingle(cpCards, retCards, f); ret {
			retCards = del
		}

	} else {
		for _, card := range cpCards {
			if card != InvalideCard && Value32(card) > kind.min {
				retCards = append(retCards, card)
				break
			}
		}
		if ret, del := MaxSingle(cpCards, retCards, f); ret {
			retCards = del
			if Value32(retCards[0]) <= kind.min {
				retCards = []int32{}
			}
		}
	}
	retkind = GetCardKind(retCards)
	return
}

func findKindCommon(m map[int32]int32, n int32) (res []*KindOfCard) {

	for i := int32(0); i <= POKER_2; i++ {
		if m[i] >= n {
			card := []int32{}
			for num := int32(0); num < n; num++ {
				card = append(card, i)
			}

			res = append(res, GetCardKind(card))
		}
	}
	return
}

// 双四
func findKindTwinFour(m map[int32]int32, n int32) (res []*KindOfCard) {
	card := []int32{}
	k := 0
	for i := int32(0); i <= POKER_2; i++ {
		if m[i] >= n {
			for num := int32(0); num < n; num++ {
				card = append(card, i)
			}
			k++
		}
		if k == 2 {
			res = append(res, GetCardKind(card))
			break
		}
	}
	return
}

func haveStraightLine(m map[int32]int32, num int32, len int32, min int32) bool {
	if min+len > POKER_2 { // 2不能带
		return false
	}
	for i := min; i < min+len; i++ {
		if m[i] < num {
			return false
		}
	}
	return true
}

// 连牌
func findStraight(m map[int32]int32, num int32, len int32) (res []*KindOfCard) {

	max := 11 - len
	min := int32(0)
	if m[-2] > 0 {
		min = -2
	} else if m[-1] > 0 { // -1 ->2
		min = -1
	}
	for ; min <= max; min++ {
		if haveStraightLine(m, num, len, min) {
			if min == -2 && len < 6 { // 没必要做连牌
				continue
			}
			if min == -1 && len < 5 {
				continue
			}
			card := []int32{}
			for num := int32(0); num < len; num++ {
				card = append(card, min+num)
			}
			res = append(res, GetCardKind(card))
		}
	}

	return
}

func allfindStraight(m map[int32]int32, num int32, len int32) (res []*KindOfCard) {
	for ilen := len; ; ilen++ {
		var flag bool // 默认false 单联判断成功就继续
		max := 11 - ilen
		min := int32(0)

		if m[-2] > 0 {
			min = -2
		} else if m[-1] > 0 { // -1 ->2
			min = -1
		}
		for ; min <= max; min++ {
			if haveStraightLine(m, num, ilen, min) {
				if min == -2 && len < 6 { // 没必要做连牌
					continue
				}
				if min == -1 && len < 5 {
					continue
				}
				card := []int32{}
				for num := int32(0); num < ilen; num++ {
					card = append(card, min+num)
				}
				res = append(res, GetCardKind(card))
				flag = true
			}
		}
		if !flag {
			break
		}
	}
	return
}

// 超时出牌 TODO
func TickOut(cards []int32, kind *KindOfCard, f bool) (delCards []int32) {
	cpCards := append([]int32{}, cards...)

	sort.Slice(cpCards, func(i, j int) bool {
		v_i := Value(cpCards[i])
		v_j := Value(cpCards[j])
		c_i := Color(cpCards[i])
		c_j := Color(cpCards[j])
		if v_i > v_j {
			return false
		} else if v_i == v_j {
			return c_i < c_j
		}
		return true
	})
	var retkind *KindOfCard
	if kind == nil || kind.num == 0 {
		retkind = GetSingle(cpCards, kind, f)

	} else {
		retkind = PressOut(kind, cpCards, f)
	}
	delCards = retkind.OutPokers(cpCards)
	return
}

// 根据上家牌型是否需要额外延迟出牌时间(s)
func NeedExDelay(lastCards []int32) bool {

	return false
}

// 计算输家输分数
func GetLoseScore(cards [HandCardNum]int32, baopei bool) (loseScore int32) {

	//cpCards := []int32{}
	num := int32(0)
	flag := false
	for _, card := range cards {
		if card != InvalideCard {
			if !flag && Value32(card) == POKER_2 {
				flag = true
				loseScore += Baopei2
			}
			//cpCards = append(cpCards, card)
			num++
		}
	}
	if num == HandCardNum {
		loseScore += Treo
	} else {
		loseScore += num
	}
	if baopei { // 庄家赔付
		loseScore -= Baopei2
	}

	return
}
