package thirteen

import (
	"sort"
)

// DelCards 从cards里边删除arr
func DelCards(cards []int, arr []int) []int {
	c := make([]int, len(cards))
	s := make([]int, len(arr))
	copy(c, cards)
	copy(s, arr)
	for i := 0; i < len(arr); i++ {
		for k, v := range c {
			a := false
			for m, n := range s {
				if v == n {
					a = true
					c = append(c[:k], c[k+1:]...)
					s = append(s[:m], s[m+1:]...)
					break
				}
			}
			if a {
				break
			}
		}
		if len(s) == 0 {
			break
		}
	}
	return c
}

func getLaiZiCards(cards []int, lai []int) []int {
	var ret []int
	for k, v := range cards {
		if v < 0 {
			continue
		}
		for _, vv := range lai {
			if vv < 0 {
				continue
			}
			if v == vv {
				ret = append(ret, v)
				cards[k] = -1
				break
			}
		}
	}
	return ret
}

func remainCards(cards, lai []int) (remainCount int, cardsLaiZi []int, cardsCount [20]int) {
	ret := [20]int{}
	count := 0
	cardsLaiZi = getLaiZiCards(cards, lai)
	for _, v := range cards {
		if v < 0 {
			continue
		}
		count++
		ret[ToLogic(v)]++
	}
	return count, cardsLaiZi, ret
}

func findCardByLogic(cards []int, logicValue, count int) []int {
	var ret []int
	for k, v := range cards {
		if v < 0 {
			continue
		}
		if ToLogic(v) == logicValue {
			ret = append(ret, v)
			cards[k] = -1
		}
		if len(ret) >= count {
			break
		}
	}
	return ret
}

func findCardByLogic2(cards []int, logicValue, count int) []int {
	var ret []int
	for _, v := range cards {
		if v < 0 {
			continue
		}
		if ToLogic(v) == logicValue {
			ret = append(ret, v)
			//cards[k] = -1
		}
		if len(ret) >= count {
			break
		}
	}
	return ret
}

// FindMaxPairs 找最大对子
func FindMaxPairs(cards, lai []int) (ret []int, change []int) {
	cs := make([]int, len(cards))
	copy(cs, cards)
	sort.Sort(sort.Reverse(sort.IntSlice(cs)))
	_, cardsLaiZi, cardsCount := remainCards(cs, lai)
	for i := 12; i >= 0; i-- {
		switch cardsCount[i] {
		case 0:
			if len(cardsLaiZi) >= 2 {
				ret = cardsLaiZi[:2]
				change = []int{51, 51} // AA
				return
			}
		case 1:
			if len(cardsLaiZi) > 0 {
				ret = append(findCardByLogic(cs, i, 1), cardsLaiZi[0])
				change = []int{ret[0], i + 3*13}
				return
			}
		default:
			ret = findCardByLogic(cs, i, 2)
			change = []int{ret[0], ret[1]}
			return
		}
	}
	return
}

// FindMaxThreeAAA 找最大三条
func FindMaxThreeAAA(cards, lai []int) (ret []int, change []int) {
	cs := make([]int, len(cards))
	copy(cs, cards)
	sort.Sort(sort.Reverse(sort.IntSlice(cs)))
	_, cardsLaiZi, cardsCount := remainCards(cs, lai)
	for i := 12; i >= 0; i-- {
		switch cardsCount[i] {
		case 0:
			if len(cardsLaiZi) >= 3 {
				ret = cardsLaiZi[:3]
				change = []int{51, 51, 51} //AAA
				return
			}
		case 1:
			if len(cardsLaiZi) > 1 {
				ret = append(findCardByLogic(cs, i, 1), cardsLaiZi[:2]...)
				change = []int{ret[0], i + 3*13, i + 3*13}
				return
			}
		case 2:
			if len(cardsLaiZi) > 0 {
				ret = append(findCardByLogic(cs, i, 2), cardsLaiZi[0])
				change = []int{ret[0], ret[1], i + 3*13}
				return
			}
		default:
			ret = findCardByLogic(cs, i, 3)
			change = []int{ret[0], ret[1], ret[2]}
			return
		}
	}
	return
}

// FindMaxFlush 找最大顺子
// 逆序返回，癞子填充
func FindMaxFlush(cards, lai []int) (ret []int, change []int) {
	cs := make([]int, len(cards))
	copy(cs, cards)
	sort.Sort(sort.Reverse(sort.IntSlice(cs)))
	_, cardsLaiZi, cardsCount := remainCards(cs, lai)
	for i := 12; i >= 4; i-- { // 起始顺子逻辑值
		var a, b int
		for j := 0; j < 5; j++ { // 顺子都是5个
			if cardsCount[i-j] > 0 {
				a++
			} else {
				b++
			}
		}
		if b <= len(cardsLaiZi) { // 癞子足够
			r := [5]int{}
			r2 := [5]int{}
			l := 0
			for j := 0; j < 5; j++ {
				if cardsCount[i-j] > 0 {
					r[j] = findCardByLogic(cs, i-j, 1)[0]
					r2[j] = r[j]
				} else {
					r[j] = cardsLaiZi[l]
					l++
					r2[j] = i - j + 3*13
				}
			}
			ret = r[:]
			change = r2[:]
			return
		}
	}

	// 找 A,2,3...
	var a, b int
	for i := 0; i < 4; i++ {
		if cardsCount[i] > 0 {
			a++
		} else {
			b++
		}
	}
	if cardsCount[12] > 0 {
		a++
	} else {
		b++
	}

	if b <= len(cardsLaiZi) { // 癞子足够
		r := [5]int{}
		r2 := [5]int{}
		l := 0

		for i := 3; i >= 0; i-- {
			if cardsCount[i] > 0 {
				r[3-i] = findCardByLogic(cs, i, 1)[0]
				r2[3-i] = r[3-i]
			} else {
				r[3-i] = cardsLaiZi[l]
				l++
				r2[3-i] = i + 3*13
			}
		}

		if cardsCount[12] > 0 {
			r[4] = findCardByLogic(cs, 12, 1)[0]
			r2[4] = r[4]
		} else {
			r[4] = cardsLaiZi[l]
			l++
			r2[4] = 12 + 3*13
		}
		ret = r[:]
		change = r2[:]
		return
	}

	return
}

// FindMaxSameColors 找最大同花
// 逆序返回,癞子追加
func FindMaxSameColors(cards, lai []int) (ret []int, change []int) {
	cs := make([]int, len(cards))
	copy(cs, cards)
	sort.Sort(sort.Reverse(sort.IntSlice(cs)))
	//_, cardsLaiZi, _ := remainCards(cs, lai)
	cardsLaiZi := getLaiZiCards(cs, lai)
	m := [4][]int{}
	for _, v := range cs {
		if v >= 0 {
			m[ToColor(v)] = append(m[ToColor(v)], v)
		}
	}
	for i := 3; i >= 0; i-- {
		if len(m[i])+len(cardsLaiZi) >= 5 {
			if len(m[i]) >= 5 {
				ret = m[i][:5]
				change = make([]int, 5)
				copy(change, ret)
				return
			}
			ret = append(m[i], cardsLaiZi[:5-len(m[i])]...)
			change = make([]int, 5)
			copy(change, m[i])
			for j := len(m[i]); j < 5; j++ {
				change[j] = 12 + i*13
			}
			return
		}
	}
	return
}

// FindMaxGourdCards 找最大葫芦
// 三条在前对子在后
func FindMaxGourdCards(cards, lai []int) (ret []int, change []int) {
	// 找最大三条,再找最大对子
	r, c := FindMaxThreeAAA(cards, lai)
	if len(r) == 0 {
		return
	}
	rr, cc := FindMaxPairs(DelCards(cards, r), lai)
	if len(rr) == 0 {
		return
	}
	return append(r, rr...), append(c, cc...)
}

// FindMaxFourAAAA 找最大铁支
func FindMaxFourAAAA(cards, lai []int) (ret []int, change []int) {
	cs := make([]int, len(cards))
	copy(cs, cards)
	sort.Sort(sort.Reverse(sort.IntSlice(cs)))
	_, cardsLaiZi, cardsCount := remainCards(cs, lai)
	for i := 12; i >= 0; i-- {
		switch cardsCount[i] {
		case 0:
			if len(cardsLaiZi) >= 4 {
				ret = cardsLaiZi[:4]
				change = []int{51, 51, 51, 51}
				return
			}
		case 1:
			if len(cardsLaiZi) >= 3 {
				ret = append(findCardByLogic(cs, i, 1), cardsLaiZi[:3]...)
				change = []int{ret[0], i + 3*13, i + 3*13, i + 3*13}
				return
			}
		case 2:
			if len(cardsLaiZi) > 1 {
				ret = append(findCardByLogic(cs, i, 2), cardsLaiZi[:2]...)
				change = []int{ret[0], ret[1], i + 3*13, i + 3*13}
				return
			}
		case 3:
			if len(cardsLaiZi) > 0 {
				ret = append(findCardByLogic(cs, i, 3), cardsLaiZi[0])
				change = []int{ret[0], ret[1], ret[2], i + 3*13}
				return
			}
		default:
			ret = findCardByLogic(cs, i, 4)
			change = make([]int, 4)
			copy(change, ret)
			return
		}
	}
	return
}

// FindMaxSameColorFlush 找最大同花顺
func FindMaxSameColorFlush(cards, lai []int) (ret []int, change []int) {
	cs := make([]int, len(cards))
	copy(cs, cards)
	sort.Sort(sort.Reverse(sort.IntSlice(cs)))
	_, cardsLaiZi, _ := remainCards(cs, lai)
	m := [4][]int{}
	for _, v := range cs {
		if v >= 0 {
			m[ToColor(v)] = append(m[ToColor(v)], v)
		}
	}
	for i := 3; i >= 0; i-- {
		a := append(m[i], cardsLaiZi...)
		r, c := FindMaxFlush(a, lai)
		if len(r) > 0 {
			// 修改一下花色
			for j := 0; j < 5; j++ {
				c[j] = ToLogic(c[j]) + i*13
			}
			return r, c
		}
	}
	return
}

// FindAllFlush 找所有顺子
func FindAllFlush(cards []int, lai []int) [][]int {
	var ret [][]int
	cs := make([]int, len(cards))
	copy(cs, cards)
	sort.Sort(sort.Reverse(sort.IntSlice(cs)))
	_, cardsLaiZi, cardsCount := remainCards(cs, lai)
	for i := 12; i >= 4; i-- { // 起始顺子逻辑值
		var a, b int
		for j := 0; j < 5; j++ { // 顺子都是5个
			if cardsCount[i-j] > 0 {
				a++
			} else {
				b++
			}
		}
		if b <= len(cardsLaiZi) { // 癞子足够
			r := [5]int{}
			//r2 := [5]int{}
			l := 0
			for j := 0; j < 5; j++ {
				if cardsCount[i-j] > 0 {
					r[j] = findCardByLogic2(cs, i-j, 1)[0]
					//r2[j] = r[j]
				} else {
					r[j] = cardsLaiZi[l]
					l++
					//r2[j] = i - j + 3*13
				}
			}
			ret = append(ret, r[:])
		}
	}

	// 找 A,2,3...
	var a, b int
	for i := 0; i < 4; i++ {
		if cardsCount[i] > 0 {
			a++
		} else {
			b++
		}
	}
	if cardsCount[12] > 0 {
		a++
	} else {
		b++
	}

	if b <= len(cardsLaiZi) { // 癞子足够
		r := [5]int{}
		//r2 := [5]int{}
		l := 0

		for i := 3; i >= 0; i-- {
			if cardsCount[i] > 0 {
				r[3-i] = findCardByLogic2(cs, i, 1)[0]
				//r2[3-i] = r[3-i]
			} else {
				r[3-i] = cardsLaiZi[l]
				l++
				//r2[3-i] = i + 3*13
			}
		}

		if cardsCount[12] > 0 {
			r[4] = findCardByLogic2(cs, 12, 1)[0]
			//r2[4] = r[4]
		} else {
			r[4] = cardsLaiZi[l]
			l++
			//r2[4] = 12 + 3*13
		}
		ret = append(ret, r[:])
	}

	return ret
}

// FindAllSameColorFlush 找所有同花顺
func FindAllSameColorFlush(cards []int, lai []int) [][]int {
	var ret [][]int
	cs := make([]int, len(cards))
	copy(cs, cards)
	sort.Sort(sort.Reverse(sort.IntSlice(cs)))
	_, cardsLaiZi, _ := remainCards(cs, lai)
	m := [4][]int{}
	for _, v := range cs {
		if v >= 0 {
			m[ToColor(v)] = append(m[ToColor(v)], v)
		}
	}
	for i := 3; i >= 0; i-- {
		a := append(m[i], cardsLaiZi...)
		r := FindAllFlush(a, lai)
		ret = append(ret, r...)
	}
	return ret
}

// FindMaxFive 找最大五同
func FindMaxFive(cards, lai []int) (ret []int, change []int) {
	cs := make([]int, len(cards))
	copy(cs, cards)
	sort.Sort(sort.Reverse(sort.IntSlice(cs)))
	_, cardsLaiZi, cardsCount := remainCards(cs, lai)
	for i := 12; i >= 0; i-- {
		switch cardsCount[i] {
		case 0:
			if len(cardsLaiZi) >= 5 {
				ret = cardsLaiZi[:5]
				change = []int{51, 51, 51, 51}
				return
			}
		case 1:
			if len(cardsLaiZi) >= 4 {
				ret = append(findCardByLogic(cs, i, 1), cardsLaiZi[:4]...)
				change = []int{ret[0], i + 3*13, i + 3*13, i + 3*13, i + 3*13}
				return
			}
		case 2:
			if len(cardsLaiZi) >= 3 {
				ret = append(findCardByLogic(cs, i, 2), cardsLaiZi[:3]...)
				change = []int{ret[0], ret[1], i + 3*13, i + 3*13, i + 3*13}
				return
			}
		case 3:
			if len(cardsLaiZi) >= 2 {
				ret = append(findCardByLogic(cs, i, 3), cardsLaiZi[:2]...)
				change = []int{ret[0], ret[1], ret[2], i + 3*13, i + 3*13}
				return
			}
		case 4:
			if len(cardsLaiZi) >= 1 {
				ret = append(findCardByLogic(cs, i, 3), cardsLaiZi[0])
				change = []int{ret[0], ret[1], ret[2], ret[3], i + 3*13}
				return
			}

		default:
			ret = findCardByLogic(cs, i, 5)
			change = make([]int, 5)
			copy(change, ret)
			return
		}
	}
	return
}

func isType(cards []int, lai []int, n int) bool {
	if len(cards) < 3 {
		return false
	}
	switch n {
	case PokersTypeFive:
		//找五同
		card, _ := FindMaxFive(cards, lai)
		if len(card) != 0 {
			return true
		}
	case PokersTypeStraightFlush:
		//找同花顺
		card, _ := FindMaxSameColorFlush(cards, lai)
		if len(card) != 0 {
			return true
		}
	case PokersTypeFour:
		//找铁支
		card, _ := FindMaxFourAAAA(cards, lai)
		if len(card) != 0 {
			return true
		}
	case PokersTypeFullHouse:
		//找葫芦
		card, _ := FindMaxGourdCards(cards, lai)
		if len(card) != 0 {
			return true
		}
	case PokersTypeFlush:
		//找同花
		card, _ := FindMaxSameColors(cards, lai)
		if len(card) != 0 {
			return true
		}
	case PokersTypeStraight:
		//找顺子
		card, _ := FindMaxFlush(cards, lai)
		if len(card) != 0 {
			return true
		}
	case PokersTypeThree:
		//找三条
		card, _ := FindMaxThreeAAA(cards, lai)
		if len(card) != 0 {
			return true
		}
	case PokersTypeTwoPairs:
		//找两对子
		if len(cards) == 3 {
			return false
		}
		card, _ := FindMaxPairs(cards, lai)
		if len(card) != 0 {
			card1, _ := FindMaxPairs(DelCards(cards, card), lai)
			if len(card1) != 0 {
				return true
			}
		}
	case PokersTypePair:
		//找对子
		card, _ := FindMaxPairs(cards, lai)
		if len(card) != 0 {
			return true
		}
	}
	return false
}

func GetType(cards []int, lai []int) int {
	if len(cards) < 3 {
		return 0
	}
	b := PokersTypeFive
	if len(cards) == 3 {
		b = PokersTypeThree
	}
	for i := b; i < PokersTypeMax; i++ {
		if isType(cards, lai, i) {
			return i
		}
	}
	return PokersTypeOne
}
