package controller

import (
	"strconv"

	"git.lxtend.com/lixiangwuxian/qqbot/handler/blackjack/model"
	"git.lxtend.com/lixiangwuxian/qqbot/handler/blackjack/util"
)

type BackJackSimulator struct {
	deck        *model.Deck
	dealerCards *model.Deck
	playerCards *model.Deck
	dealerScore int
	playerScore int
	status      util.Status
}

func NewBlackJackSimulator() *BackJackSimulator {
	simulator := &BackJackSimulator{
		deck:        model.NewDeck(),
		dealerCards: model.NewDeck(),
		playerCards: model.NewDeck(),
	}

	simulator.Init()
	return simulator
}

func initDeck(deck *model.Deck) *model.Deck {
	colors := []string{"Spade", "Heart", "Diamond", "Club"}

	for _, color := range colors {
		for i := 2; i <= 10; i++ {
			deck.Add(model.NewCard(color, strconv.Itoa(i), []int{i}, true))
		}

		for _, name := range []string{"J", "Q", "K"} {
			deck.Add(model.NewCard(color, name, []int{10}, true))
		}

		deck.Add(model.NewCard(color, "A", []int{1, 11}, true))
	}

	return deck.Shuffle()
}

func initDealerCards(dealerCards *model.Deck, deck *model.Deck) *model.Deck {
	if firstCard := deck.Draw(); deck != nil {
		dealerCards.Add(firstCard.Flip())
	}

	if secondCard := deck.Draw(); deck != nil {
		dealerCards.Add(secondCard)
	}
	return dealerCards
}

func initPlayerCards(playerCards *model.Deck, deck *model.Deck) *model.Deck {
	if firstCard := deck.Draw(); deck != nil {
		playerCards.Add(firstCard)
	}

	if secondCard := deck.Draw(); deck != nil {
		playerCards.Add(secondCard)
	}
	return playerCards
}

func (simulator *BackJackSimulator) Init() *BackJackSimulator {
	simulator.deck = model.NewDeck()
	simulator.dealerCards = model.NewDeck()
	simulator.playerCards = model.NewDeck()

	simulator.deck = initDeck(simulator.deck)
	simulator.dealerCards = initDealerCards(simulator.dealerCards, simulator.deck)
	simulator.playerCards = initPlayerCards(simulator.playerCards, simulator.deck)

	simulator.dealerScore, simulator.playerScore = 0, 0
	simulator.status = util.INITIALIZED

	return simulator
}

func (simulator *BackJackSimulator) Hit() *BackJackResponse {
	if simulator.status == util.FAILED || simulator.status == util.WINNED || simulator.status == util.DRAW {
		return NewBlackJackResponse(400, "[🐧] You have failed in this Blackjack game !\n")
	}

	if card := simulator.deck.Draw(); card != nil {
		simulator.playerCards.Add(card)
		simulator.playerScore = 0

		for _, card := range simulator.playerCards.Cards() {
			simulator.playerScore += card.Value[0]
		}

		if simulator.playerScore > 21 {
			simulator.status = util.FAILED
			return NewBlackJackResponse(400, "[🐧] Your total score exceeds 21 ! You lose !\n")
		}
	}

	return NewBlackJackResponse(200, "[🐧] You have drawn a card !\n")
}

func (simulator *BackJackSimulator) Stand() *BackJackResponse {
	if simulator.status == util.FAILED || simulator.status == util.WINNED || simulator.status == util.DRAW {
		return NewBlackJackResponse(400, "[🐧] You have failed in this Blackjack game !\n")
	}

	simulator.dealerScore, simulator.playerScore = 0, 0
	maxDealerScore, maxPlayerScore, minDealerScore, minPlayerScore := 0, 0, 0, 0

	for _, card := range simulator.dealerCards.Cards() {
		if !card.Visible {
			card.Flip()
		}

		if card.Name == "A" {
			maxDealerScore += card.Value[1]
			minDealerScore += card.Value[0]
		} else {
			maxDealerScore += card.Value[0]
			minDealerScore += card.Value[0]
		}
	}

	for _, card := range simulator.playerCards.Cards() {
		if card.Name == "A" {
			maxPlayerScore += card.Value[1]
			minPlayerScore += card.Value[0]
		} else {
			maxPlayerScore += card.Value[0]
			minPlayerScore += card.Value[0]
		}
	}

	if maxDealerScore < 17 {
		for maxDealerScore < 17 {
			if card := simulator.deck.Draw(); card != nil {
				simulator.dealerCards.Add(card)
				if card.Name == "A" {
					maxDealerScore += card.Value[1]
					minDealerScore += card.Value[0]
				} else {
					maxDealerScore += card.Value[0]
					minDealerScore += card.Value[0]
				}
			}

			if minDealerScore > 21 {
				simulator.status = util.WINNED
				return NewBlackJackResponse(400, "[🐧] The dealer burst and you have won the game !\n")
			}
		}
	}

	if maxDealerScore > maxPlayerScore {
		simulator.status = util.FAILED
		return NewBlackJackResponse(400, "[🐧] The dealer wins the game !\n")
	} else if maxDealerScore < maxPlayerScore {
		simulator.status = util.WINNED
		return NewBlackJackResponse(400, "[🐧] You have won the game !\n")
	} else if maxDealerScore == maxPlayerScore {
		simulator.status = util.DRAW
		return NewBlackJackResponse(200, "[🐧] It is a draw !\n")
	}

	return NewBlackJackResponse(400, "[🐧] Unrecognized Error !\n")
}

func (simulator *BackJackSimulator) GetDealerCards() *model.Deck {
	return simulator.dealerCards
}

func (simulator *BackJackSimulator) GetPlayerCards() *model.Deck {
	return simulator.playerCards
}

func (simulator *BackJackSimulator) GetStatus() util.Status {
	return simulator.status
}
