from random import choice
from typing import List

from server.model.card import Card
from server.model.color import Color
from server.model.value import Value
from server.model.hand import Hand


def hand(cards: List[Card]) -> Hand:
    return Hand(cards=cards)


def card(value: Value, color: Color) -> Card:
    return Card(value=value, color=color)


def carre(value) -> Hand:
    return hand([
        card(value, Color.Hearts),
        card(value, Color.Clubs),
        card(value, Color.Diamonds),
        card(value, Color.Spades)
    ])


def full(value_aux: Value,
         value_par: Value) -> Hand:
    return hand([
        card(value_aux, Color.Hearts),
        card(value_aux, Color.Clubs),
        card(value_aux, Color.Diamonds),
        card(value_par, Color.Hearts),
        card(value_par, Color.Clubs)
    ])


def brelan(value) -> Hand:
    return hand([
        card(value, Color.Hearts),
        card(value, Color.Clubs),
        card(value, Color.Diamonds)
    ])


def pair(value) -> Hand:
    return hand([
        card(value, Color.Hearts),
        card(value, Color.Clubs)
    ])


def single(low_value) -> Hand:
    return hand([
        card(low_value, Color.Hearts)
    ])


def double_pair(value: Value, other: Value = None):
    # Ensure no carre
    if not other or other == value:
        other = Value.Two if value == Value.Three else Value.Three
    assert other != value

    return hand([
        # Pair of value
        card(value, Color.Hearts),
        card(value, Color.Clubs),
        # And pair of twos or threes
        card(other, Color.Hearts),
        card(other, Color.Clubs)
    ])


def all_options() -> List[Hand]:
    hands = []

    carres = [carre(value) for value in Value]
    brelans = [brelan(value) for value in Value]
    pairs = [pair(value) for value in Value]
    singles = [single(value) for value in Value]

    hands.extend(carres)
    hands.extend(brelans)
    hands.extend(pairs)
    hands.extend(singles)
    for b in brelans:
        for p in pairs:
            if not any([c in b.cards for c in p.cards]):  # Valid full
                hands.append(hand([*b.cards, *p.cards]))
    return hands


options = all_options()


def random_option() -> Hand:
    return choice(options)
