# import itertools
import random


def shoe(n_of_decks: int = 1) -> list:
    """Create shuffled shoe of n decks of cards

    Args:
        n_of_decks (int, optional): number of decks. Defaults to 1.

    Returns:
        list: shoe- shuffled decks of cards
    """
    vals = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'jack', 'queen', 'king', 'ace']
    suits = ['spades', 'clubs', 'hearts', 'diamonds']

    deck = []
    for _ in range(n_of_decks):
        for _ in suits:
            deck.extend(vals)
        # deck.extend(itertools.product(vals, suits))

    random.shuffle(deck)
    return deck

def cards_eval(hand: list) -> list:
    """Evaluate hand value. Will return two values if there is an ace
    in the hand and both values are below 21.

    Args:
        hand (list): list of cards

    Returns:
        list: returns a list of values of the hand
    """
    evaluation = [0, 0]
    for value in hand:
        if value in ['jack', 'queen', 'king']:
            evaluation[0] += 10
            evaluation[1] += 10
        elif value == 'ace':
            evaluation[0] += 1
            evaluation[1] += 11
        else:
            evaluation[0] += int(value)
            evaluation[1] += int(value)
    if evaluation[0] == evaluation[1]:
        return [evaluation[0]]
    elif evaluation[1] > 21:
        return [evaluation[0]]
    else:
        return evaluation # both values returned

def dealer(hand: list, shoe: iter) -> int:
    """Dealer hand resolution

    Args:
        hand (list): dealer hand
        shoe (iter): iterator of shoe

    Returns:
        int: dealer hand value
    """
    evaluation = cards_eval(hand)
    while max(evaluation) <= 17: #solve soft 17
        hand.append(next(shoe))
        evaluation = cards_eval(hand)
    return max(evaluation)

def AI(hand: list, face_up: str) -> str:
    #TODO: add fuzzy logic
    """Fuzzy AI 
    possible player decision:
    'hit', 'double down', 'split', 'surrender', 'stand'
    Args:
        hand (list): player hand
        face_up (str): dealer face up card

    Returns:
        list: player decision
    """
    ### temp
    # if face_up == 'ace':
    #     return 'surrender'
    # else:
    evaluation = cards_eval(hand)
    if max(evaluation) <= 17:
        return 'hit'
    else:
        return 'stand'
    ### temp

def blackjack(shoe: iter, dealer_hand: list=[], player_hand: list =[]) -> str:
    """Single blackjack round

    Args:
        shoe (iter): shoe iterator
        dealer_hand (list, optional): dealer hand. Should be non empty only in SPLIT.
        player_hand (list, optional): player hand. Should be non empty only in SPLIT.

    Returns:
        str: game result
    """
    if dealer_hand == [] and player_hand == []:
        dealer_hand = [next(shoe), next(shoe)]
        player_hand = [next(shoe), next(shoe)]
    face_up = dealer_hand[0]
    
    decision = ''
    while decision != 'stand' or decision != 'surrender':
        decision = AI(player_hand, face_up)
        if decision == 'hit':
            player_hand.append(next(shoe))
        elif decision == 'double down':
            player_hand.append(next(shoe))
        elif decision == 'split':
            #this wont work!
            #it will need to
            #   dealer_value = dealer(dealer_hand, shoe)
            #be calculated before and passed to blackjack()
            #so both wager have the same dealer_value!
            ##this will work reccursevly
            player_hand = player_hand[0]
            blackjack(shoe, dealer_hand, player_hand)#new wager start
            #old wager continue
        elif decision == 'surrender':
            break
        elif decision == 'stand':
            break

    #dealer turn
    dealer_value = dealer(dealer_hand, shoe)
    player_value = max(cards_eval(player_hand))
    # print(dealer_value, player_value) #debug
    
    #round end
    if player_value > 21:
        return 'dealer win'
    elif dealer_value > 21:
        return 'player win'
    elif player_value > dealer_value:
        return 'player win'
    elif player_value == dealer_value:
        return 'push' #keep money, no win no lose 0$
    else:
        return 'dealer win'
    #TODO: add adidtional return with wager value like +10$ or -20$

def game_loop() -> None:
    stats = [0, 0] #wins, loses
    shoe_iter = iter(shoe(10))
    while True:
    #round start
        try:
            result = blackjack(shoe_iter)
        except StopIteration:
            break
        if result == 'player win':
            stats[0] += 1
        elif result == 'dealer win':
            stats[1] += 1
        # elif result == 'push':
        #     stats[0] += 0
        # stats[1] += 1
    return stats

# if __name__ == '__main__':
#     print(game_loop())
    
if __name__ == '__main__':
    statistics = [0, 0]
    import time
    #don't use time.time() for counting code execution time!
    start = time.perf_counter()
    for i in range(1000):
        wins, loses = game_loop()
        statistics[0] += wins
        statistics[1] += loses

    end = time.perf_counter()
    result = end - start
    print(result)
    print(statistics)
    print(statistics[0]/sum(statistics))