package tienlen

import (
	"math/rand"
	"sort"
	"time"
)

//牌序- 2, A, K, Q, J, 10, 9, 8, 7, 6, 5, 4, 3
//红桃- 51,50,49,48,47,46,45,44,43,42,41,40,39
//方片- 38,37,36,35,34,33,32,31,30,29,28,27,26
//梅花- 25,24,23,22,21,20,19,18,17,16,15,14,13
//黑桃- 12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0

const (
	POKER_CNT          = 52
	PER_CARD_COLOR_MAX = 13
	Hand_CardNum       = 13 //手牌
	Card_Value_2       = 12 //特殊牌值2
	Player_Num_Max     = 4  //桌上最大人數
	HongTao2           = 51
	FangPian2          = 38
	MeiHua2            = 25
	HeiTao2            = 12
)

// 不同牌型分值
const (
	hei2     = 0
	fang2    = 3
	hong2    = 5
	zhadan   = 20
	liandui5 = 21
	liandui4 = 18
	liandui3 = 15
	shunzi8  = 15
	shunzi7  = 10
	shunzi6  = 5
	sanzhang = 3
)

const (
	yl_hei2     = 0
	yl_fang2    = 3
	yl_hong2    = 5
	yl_zhadan   = 30
	yl_liandui5 = 21
	yl_liandui4 = 18
	yl_liandui3 = 15
	yl_shunzi8  = 15
	yl_shunzi7  = 10
	yl_shunzi6  = 5
	yl_sanzhang = 15
)

type Card int

type Poker struct {
	buf       [POKER_CNT]Card
	copyBuf   [POKER_CNT]Card
	tianhuBuf [POKER_CNT]Card
	isTianhu  bool
}

func (this *Poker) GetPokerBuf() [POKER_CNT]Card {
	return this.buf
}

func (this *Poker) CopyPokerBuf() {
	for i := 0; i < len(this.buf); i++ {
		this.copyBuf[i] = this.buf[i]
	}
}

func (this *Poker) UncopyPokerBuf() {
	for i := 0; i < len(this.copyBuf); i++ {
		this.buf[i] = this.copyBuf[i]
		this.copyBuf[i] = Card(i)
	}
}

func (this *Poker) TianhuPokerBuf() {
	for i := 0; i < len(this.buf); i++ {
		this.tianhuBuf[i] = this.buf[i]
	}
	this.isTianhu = true
}

func (this *Poker) UnTianhuPokerBuf() {
	for i := 0; i < len(this.tianhuBuf); i++ {
		this.buf[i] = this.tianhuBuf[i]
		this.tianhuBuf[i] = Card(i)
	}
	this.isTianhu = false
}

func (this *Poker) IsTianhuPoker() bool {
	return this.isTianhu
}

func NewPoker() *Poker {
	p := &Poker{}
	p.init()
	return p
}

func (this *Poker) init() {
	for i := int32(0); i < POKER_CNT; i++ {
		this.buf[i] = Card(i)
	}
	rand.Seed(time.Now().UnixNano())
	this.Shuffle()
}

func (this *Poker) Shuffle() {
	for i := int32(0); i < POKER_CNT; i++ {
		j := rand.Intn(int(i) + 1)
		this.buf[i], this.buf[j] = this.buf[j], this.buf[i]
	}
}

// GetCardsGrade 给手牌打分
func GetCardsGrade(cards []int32, yl bool) int {
	grade := 0
	cpCards := []int32{}
	for _, card := range cards {
		if card != InvalideCard {
			cpCards = append(cpCards, card)
			grade += Value(card) + 1 // 基础分
		}
	}

	if Have2FourBomb(cpCards) || Have6StraightTwin(cpCards) || Have12Straight(cpCards) {
		return 9999
	}

	//找单2
	for i := 0; i < len(cpCards); i++ {
		card := cpCards[i]
		switch card {
		case HongTao2:
			if yl {
				grade += yl_hong2
			} else {
				grade += hong2
			}
			cpCards = append(cpCards[:i], cpCards[i+1:]...)
			i--
		case FangPian2:
			if yl {
				grade += yl_fang2
			} else {
				grade += fang2
			}
			cpCards = append(cpCards[:i], cpCards[i+1:]...)
			i--
		case MeiHua2, HeiTao2:
			if yl {
				grade += yl_hei2
			} else {
				grade += hei2
			}
			cpCards = append(cpCards[:i], cpCards[i+1:]...)
			i--
		}
	}

	// 找炸弹
	if len(cpCards) >= 4 {
		mapBomb := make(map[int32]int)
		for _, card := range cpCards {
			mapBomb[int32(Value(card))]++
		}
		bombValue := []int32{}
		for card, num := range mapBomb {
			if num == 4 {
				bombValue = append(bombValue, card)
			}
		}
		if len(bombValue) > 0 {
			findCards := []int32{}
			for _, card := range bombValue {
				for i := int32(0); i < 4; i++ {
					findCards = append(findCards, card+(i*PER_CARD_COLOR_MAX))
					cpCards = DelSliceInt32(cpCards, card+(i*PER_CARD_COLOR_MAX))
				}
			}
			if yl {
				grade += len(bombValue) * yl_zhadan
			} else {
				grade += len(bombValue) * zhadan
			}
		}
	}

	//找五连
	if len(cpCards) >= 10 {
		sort.Slice(cpCards, func(i, j int) bool {
			if cpCards[i] > cpCards[j] {
				return false
			}
			return true
		})
		map5STwin := make(map[int32]int32)
		for _, card := range cpCards {
			map5STwin[int32(Value(card))]++
		}
		Value5STwin := []int32{}
		for card, num := range map5STwin {
			if num >= 2 {
				Value5STwin = append(Value5STwin, card)
			}
		}
		sort.Slice(Value5STwin, func(i, j int) bool {
			if Value5STwin[i] > Value5STwin[j] {
				return false
			}
			return true
		})
		if len(Value5STwin) > 0 {
			tmpPairs := FindOneStraightWithWidth(5, Value5STwin)
			if len(tmpPairs) > 0 {
				findCards := []int32{}
				for _, card := range tmpPairs {
					delC := 0
					for i := 0; i < len(cpCards); i++ {
						if cpCards[i] == InvalideCard {
							continue
						}
						if int32(Value(cpCards[i])) == card && (delC < 2) { //删除2次
							findCards = append(findCards, card)
							delC++
							cpCards = append(cpCards[:i], cpCards[i+1:]...)
							i--
							continue
						}
					}
				}
				if yl {
					grade += yl_liandui5
				} else {
					grade += liandui5
				}
			}
		}
	}

	//找四连
	if len(cpCards) >= 8 {
		sort.Slice(cpCards, func(i, j int) bool {
			if cpCards[i] > cpCards[j] {
				return false
			}
			return true
		})
		map4STwin := make(map[int32]int32)
		for _, card := range cpCards {
			map4STwin[int32(Value(card))]++
		}
		Value4STwin := []int32{}
		for card, num := range map4STwin {
			if num >= 2 {
				Value4STwin = append(Value4STwin, card)
			}
		}
		sort.Slice(Value4STwin, func(i, j int) bool {
			if Value4STwin[i] > Value4STwin[j] {
				return false
			}
			return true
		})
		if len(Value4STwin) > 0 {
			tmpPairs := FindOneStraightWithWidth(4, Value4STwin)
			if len(tmpPairs) > 0 {
				findCards := []int32{}
				for _, card := range tmpPairs {
					delC := 0
					for i := 0; i < len(cpCards); i++ {
						if cpCards[i] != InvalideCard {
							if int32(Value(cpCards[i])) == card && (delC < 2) { //删除2次
								findCards = append(findCards, card)
								delC++
								cpCards = append(cpCards[:i], cpCards[i+1:]...)
								i--
								continue
							}
						}
					}
				}
				if yl {
					grade += yl_liandui4
				} else {
					grade += liandui4
				}
			}
		}
	}

	//找三连
	if len(cpCards) >= 6 {
		sort.Slice(cpCards, func(i, j int) bool {
			if cpCards[i] > cpCards[j] {
				return false
			}
			return true
		})
		map3STwin := make(map[int32]int32)
		for _, card := range cpCards {
			map3STwin[int32(Value(card))]++
		}
		Value3STwin := []int32{}
		for card, num := range map3STwin {
			if num >= 2 {
				Value3STwin = append(Value3STwin, card)
			}
		}
		sort.Slice(Value3STwin, func(i, j int) bool {
			if Value3STwin[i] > Value3STwin[j] {
				return false
			}
			return true
		})
		if len(Value3STwin) > 0 {
			tmpPairs := FindOneStraightWithWidth(3, Value3STwin)
			if len(tmpPairs) > 0 {
				findCards := []int32{}
				for _, card := range tmpPairs {
					delC := 0
					for i := 0; i < len(cpCards); i++ {
						if cpCards[i] == InvalideCard {
							continue
						}
						if int32(Value(cpCards[i])) == card && (delC < 2) { //删除2次
							findCards = append(findCards, card)
							delC++
							cpCards = append(cpCards[:i], cpCards[i+1:]...)
							i--
							continue
						}
					}
				}
				if yl {
					grade += yl_liandui3
				} else {
					grade += liandui3
				}
			}
		}
	}

	//再找三连
	if len(cpCards) >= 6 {
		sort.Slice(cpCards, func(i, j int) bool {
			if cpCards[i] > cpCards[j] {
				return false
			}
			return true
		})
		map3STwin := make(map[int32]int32)
		for _, card := range cpCards {
			map3STwin[int32(Value(card))]++
		}
		Value3STwin := []int32{}
		for card, num := range map3STwin {
			if num >= 2 {
				Value3STwin = append(Value3STwin, card)
			}
		}
		sort.Slice(Value3STwin, func(i, j int) bool {
			if Value3STwin[i] > Value3STwin[j] {
				return false
			}
			return true
		})
		if len(Value3STwin) > 0 {
			tmpPairs := FindOneStraightWithWidth(3, Value3STwin)
			if len(tmpPairs) > 0 {
				findCards := []int32{}
				for _, card := range tmpPairs {
					delC := 0
					for i := 0; i < len(cpCards); i++ {
						if cpCards[i] == InvalideCard {
							continue
						}
						if int32(Value(cpCards[i])) == card && (delC < 2) { //删除2次
							findCards = append(findCards, card)
							delC++
							cpCards = append(cpCards[:i], cpCards[i+1:]...)
							i--
							continue
						}
					}
				}
				if yl {
					grade += yl_liandui3
				} else {
					grade += liandui3
				}
			}
		}
	}
	//找8顺子
	if len(cpCards) >= 8 {
		del, tmpCards, _ := delStraight(cpCards, 8)
		if del {
			if yl {
				grade += yl_shunzi8
			} else {
				grade += shunzi8
			}
			cpCards = tmpCards
		}
	}
	// 找三张
	if len(cpCards) >= 3 {
		mapTriple := make(map[int32]int)
		for _, card := range cpCards {
			mapTriple[int32(Value(card))]++
		}
		tripleValues := []int32{}
		for card, num := range mapTriple {
			if num == 3 {
				tripleValues = append(tripleValues, card)
			}
		}
		if len(tripleValues) > 0 {
			findCards := []int32{}
			for _, value := range tripleValues {
				delC := 0
				for i := 0; i < len(cpCards); i++ {
					card := cpCards[i]
					if card != InvalideCard {
						if Value(card) == int(value) && (delC < 3) { //删除3次
							findCards = append(findCards, card)
							delC++
							cpCards = append(cpCards[:i], cpCards[i+1:]...)
							i--
							continue
						}
					}
				}
			}
			if yl {
				grade += len(tripleValues) * yl_sanzhang
			} else {
				grade += len(tripleValues) * sanzhang
			}
		}
	}
	//找7顺子
	if len(cpCards) >= 7 {
		del, tmpCards, _ := delStraight(cpCards, 7)
		if del {
			if yl {
				grade += yl_shunzi7
			} else {
				grade += shunzi7
			}
			cpCards = tmpCards
		}
	}
	//找6顺子
	if len(cpCards) >= 6 {
		del, tmpCards, _ := delStraight(cpCards, 6)
		if del {
			if yl {
				grade += yl_shunzi6
			} else {
				grade += shunzi6
			}
			cpCards = tmpCards
		}
	}
	//再找6顺子
	if len(cpCards) >= 6 {
		del, tmpCards, _ := delStraight(cpCards, 6)
		if del {
			if yl {
				grade += yl_shunzi6
			} else {
				grade += shunzi6
			}
			cpCards = tmpCards
		}
	}
	return grade
}

// 发顺子（不包括2 最少3顺子）
func delStraight(cards []int32, value int) (bool, []int32, []int32) {
	haveNeed := false
	needCards := []int32{}

	if cards == nil || len(cards) < value {
		return haveNeed, cards, needCards
	}

	mapStraights := make(map[int32]int32)
	for _, card := range cards {
		if card != InvalideCard && Value(card) != Card_Value_2 {
			mapStraights[int32(Value(card))]++
		}
	}
	valueStraights := []int32{}
	for cardValue, _ := range mapStraights {
		valueStraights = append(valueStraights, cardValue)
	}
	if len(valueStraights) > 0 {
		sort.Slice(valueStraights, func(i, j int) bool {
			if valueStraights[i] > valueStraights[j] {
				return false
			}
			return true
		})
		straights := FindStraightWithWidth(value, valueStraights)
		if len(straights) > 0 {
			randStraight := straights[rand.Intn(len(straights))] //随机一条顺子
			for _, cardValue := range randStraight {
				delC := 0
				for i := 0; i < len(cards); i++ {
					card := cards[i]
					if card == InvalideCard {
						continue
					}
					if int32(Value(card)) == cardValue && (delC < 1) { //删除1次
						delC++
						needCards = append(needCards, card)
						cards = append(cards[:i], cards[i+1:]...)
						i--
						continue
					}
				}
			}
			haveNeed = true
		}
	}

	return haveNeed, cards, needCards
}

// 发连对（不包括2 最少2顺子）
func delStraightTwin(cards []int32, value int) (bool, []int32, []int32) {
	haveNeed := false
	needCards := []int32{}

	if cards == nil || len(cards) < value {
		return haveNeed, cards, needCards
	}

	mapStraights := make(map[int32]int32)
	for _, card := range cards {
		if card != InvalideCard && Value(card) != Card_Value_2 {
			mapStraights[int32(Value(card))]++
		}
	}
	valueStraights := []int32{}
	for cardValue, count := range mapStraights {
		if count >= 2 /*&& !common.InSliceInt32(valueStraights, cardValue)*/ {
			valueStraights = append(valueStraights, cardValue)
		}
	}
	if len(valueStraights) > 0 {
		sort.Slice(valueStraights, func(i, j int) bool {
			if valueStraights[i] > valueStraights[j] {
				return false
			}
			return true
		})
		straights := FindStraightWithWidth(value, valueStraights)
		if len(straights) > 0 {
			randStraight := straights[rand.Intn(len(straights))] //随机一条顺子
			for _, cardValue := range randStraight {
				delC := 0
				for i := 0; i < len(cards); i++ {
					card := cards[i]
					if card == InvalideCard {
						continue
					}
					if int32(Value(card)) == cardValue && (delC < 2) { //删除2次
						delC++
						needCards = append(needCards, card)
						cards = append(cards[:i], cards[i+1:]...)
						i--
						continue
					}
				}
			}
			haveNeed = true
		}
	}

	return haveNeed, cards, needCards
}

func SendHandCard(poker *Poker) []int {
	poker.Shuffle()
	buf := poker.GetPokerBuf()

	cardss := map[int][]int32{}
	for i, card := range buf {
		if int32(card) != InvalideCard {
			index := i / 13
			cardss[index] = append(cardss[index], int32(card))
		}
	}

	type gradeInfo struct {
		id    int
		grade int
		cards []int32
	}
	grades := []gradeInfo{}
	for i, card13 := range cardss {
		cardTmp := make([]int32, 13)
		copy(cardTmp, card13)
		grade := GetCardsGrade(cardTmp, false)
		gi := gradeInfo{
			id:    i,
			grade: grade,
			cards: card13,
		}
		grades = append(grades, gi)
	}

	sort.Slice(grades, func(i, j int) bool {
		return grades[i].grade > grades[j].grade
	})

	//fmt.Println("grades: ", grades)

	sortGrades := []int{}
	for _, grade := range grades {
		sortGrades = append(sortGrades, grade.grade)
	}
	return sortGrades
}

func MinSortCards(cs []int32) {
	sort.Slice(cs, func(i, j int) bool {
		vI := Value(cs[i])
		vJ := Value(cs[j])
		cI := Color(cs[i])
		cJ := Color(cs[j])
		if vI > vJ {
			return false
		} else if vI == vJ {
			return cI < cJ
		}
		return true
	})
}
