import dataclasses
import enum
import random

Suit = enum.Enum(
    "Suit",
    """
    CLUBS
    DIAMONDS
    HEARTS
    SPADES
""",
)

FaceValue = enum.Enum(
    "FaceValue",
    """
    ACE
    TWO
    THREE
    FOUR
    FIVE
    SIX
    SEVEN
    EIGHT
    NINE
    TEN
    JACK
    QUEEN
    KING
""",
)


@dataclasses.dataclass
class Card:
    suit: Suit
    face_value: FaceValue

    def __str__(self):
        return f"{self.face_value} of {self.suit}"


class Joker:
    def __str__(self):
        return "JOKER"


class Deck:
    def __init__(self, n_jokers=2):
        self._cards = list(Deck.generate(n_jokers=n_jokers))

    def __repr__(self):
        return f"<Deck len={len(self)}>"

    def __str__(self):
        as_string = []
        for card in self._cards:
            as_string.append(str(card))
        return "\n".join(as_string)

    def __len__(self):
        return len(self._cards)

    def draw(self):
        if len(self._cards) > 0:
            return self._cards.pop()
        return None

    def shuffle(self):
        random.shuffle(self._cards)
        return self

    def cut(self):
        cut_point = random.randint(0, len(self))
        self._cards = self._cards[cut_point:] + self._cards[:cut_point]
        return self

    @staticmethod
    def generate(n_jokers=2):
        for _ in range(n_jokers):
            yield Joker()

        for suit in Suit:
            for face_value in FaceValue:
                yield Card(suit=suit, face_value=face_value)
