package eu.jonahbauer.wizard.core.model.card;

import eu.jonahbauer.wizard.common.model.Card;
import eu.jonahbauer.wizard.core.util.Pair;
import org.junit.jupiter.api.Test;

import java.util.List;
import java.util.UUID;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

public class CardUtilsTest {
    private void performWinnerTest(List<Pair<UUID, Card>> stack, Card.Suit trumpSuit) {
        assertNotNull(CardUtils.getWinner(stack, trumpSuit));
    }

    @Test
    public void getWinner_ReturnsFirstWizard() {
        List<Pair<UUID, Card>> stack = List.of(
                Pair.of(null, Card.RED_1),
                Pair.of(null, Card.YELLOW_1),
                Pair.of(UUID.randomUUID(), Card.BLUE_WIZARD),
                Pair.of(null, Card.BLUE_JESTER),
                Pair.of(null, Card.GREEN_11),
                Pair.of(null, Card.FAIRY)
        );

        performWinnerTest(stack, Card.Suit.YELLOW);
    }

    @Test
    public void getWinner_ReturnsDragon() {
        List<Pair<UUID, Card>> stack = List.of(
                Pair.of(null, Card.RED_1),
                Pair.of(null, Card.BLUE_WIZARD),
                Pair.of(UUID.randomUUID(), Card.DRAGON),
                Pair.of(null, Card.BLUE_JESTER),
                Pair.of(null, Card.GREEN_11)
        );

        performWinnerTest(stack, Card.Suit.YELLOW);
    }

    @Test
    public void getWinner_ReturnsFairy_IfDragon() {
        List<Pair<UUID, Card>> stack = List.of(
                Pair.of(null, Card.RED_1),
                Pair.of(null, Card.BLUE_WIZARD),
                Pair.of(UUID.randomUUID(), Card.FAIRY),
                Pair.of(null, Card.DRAGON),
                Pair.of(null, Card.GREEN_11)
        );

        performWinnerTest(stack, Card.Suit.YELLOW);
    }

    @Test
    public void getWinner_ReturnsHighestTrump_IfNoWizard() {
        List<Pair<UUID, Card>> stack = List.of(
                Pair.of(null, Card.RED_1),
                Pair.of(null, Card.YELLOW_1),
                Pair.of(null, Card.BLUE_JESTER),
                Pair.of(UUID.randomUUID(), Card.YELLOW_13),
                Pair.of(null, Card.GREEN_11),
                Pair.of(null, Card.FAIRY)
        );

        performWinnerTest(stack, Card.Suit.YELLOW);
    }

    @Test
    public void getWinner_ReturnsHighestSpecialTrump_IfNoWizard() {
        List<Pair<UUID, Card>> stack = List.of(
                Pair.of(null, Card.RED_1),
                Pair.of(null, Card.YELLOW_1),
                Pair.of(null, Card.BLUE_JESTER),
                Pair.of(UUID.randomUUID(), Card.JUGGLER_YELLOW),
                Pair.of(null, Card.GREEN_11),
                Pair.of(null, Card.FAIRY)
        );

        performWinnerTest(stack, Card.Suit.YELLOW);
    }

    @Test
    public void getWinner_ReturnsHighestSpecialTrump_IfNoWizard2() {
        List<Pair<UUID, Card>> stack = List.of(
                Pair.of(null, Card.RED_1),
                Pair.of(null, Card.YELLOW_1),
                Pair.of(null, Card.BLUE_JESTER),
                Pair.of(UUID.randomUUID(), Card.CLOUD_YELLOW),
                Pair.of(null, Card.GREEN_11),
                Pair.of(null, Card.FAIRY)
        );

        performWinnerTest(stack, Card.Suit.YELLOW);
    }

    @Test
    public void getWinner_ReturnsHighestTrickSuit_IfNeitherWizardNorTrump() {
        List<Pair<UUID, Card>> stack = List.of(
                Pair.of(null, Card.RED_5),
                Pair.of(null, Card.BLUE_JESTER),
                Pair.of(UUID.randomUUID(), Card.RED_13),
                Pair.of(null, Card.YELLOW_13),
                Pair.of(null, Card.GREEN_11),
                Pair.of(null, Card.RED_7),
                Pair.of(null, Card.FAIRY)
        );

        performWinnerTest(stack, Card.Suit.BLUE);
    }

    @Test
    public void getWinner_ReturnsHighestSpecialTrickSuit_IfNeitherWizardNorTrump() {
        List<Pair<UUID, Card>> stack = List.of(
                Pair.of(null, Card.RED_5),
                Pair.of(null, Card.BLUE_JESTER),
                Pair.of(UUID.randomUUID(), Card.CLOUD_RED),
                Pair.of(null, Card.YELLOW_13),
                Pair.of(null, Card.GREEN_11),
                Pair.of(null, Card.RED_7),
                Pair.of(null, Card.FAIRY)
        );

        performWinnerTest(stack, Card.Suit.BLUE);
    }

    @Test
    public void getWinner_ReturnsHighestSpecialTrickSuit_IfNeitherWizardNorTrump2() {
        List<Pair<UUID, Card>> stack = List.of(
                Pair.of(null, Card.RED_5),
                Pair.of(null, Card.BLUE_JESTER),
                Pair.of(UUID.randomUUID(), Card.JUGGLER_RED),
                Pair.of(null, Card.YELLOW_13),
                Pair.of(null, Card.GREEN_11),
                Pair.of(null, Card.RED_7),
                Pair.of(null, Card.FAIRY)
        );

        performWinnerTest(stack, Card.Suit.BLUE);
    }

    @Test
    public void getWinner_ReturnsFirstJester_IfOnlyJester() {
        List<Pair<UUID, Card>> stack = List.of(
                Pair.of(UUID.randomUUID(), Card.GREEN_JESTER),
                Pair.of(null, Card.BLUE_JESTER),
                Pair.of(null, Card.RED_JESTER),
                Pair.of(null, Card.FAIRY),
                Pair.of(null, Card.YELLOW_JESTER)
        );

        performWinnerTest(stack, Card.Suit.RED);
    }

    @Test
    public void getWinner_ReturnsJester_IfOnlyFairyAndBomb() {
        List<Pair<UUID, Card>> stack = List.of(
                Pair.of(null, Card.FAIRY),
                Pair.of(null, Card.BOMB),
                Pair.of(UUID.randomUUID(), Card.RED_JESTER)
        );

        performWinnerTest(stack, Card.Suit.RED);
    }
    
    @Test
    public void getTrickSuit_ReturnsNone_IfEmpty() {
        List<Pair<UUID, Card>> stack = List.of();
        assertEquals(Card.Suit.NONE, CardUtils.getTrickSuit(stack));
    }

    @Test
    public void getTrickSuit_ReturnsColor() {
        List<Pair<UUID, Card>> stack = List.of(
                Pair.of(null, Card.RED_1),
                Pair.of(null, Card.YELLOW_1),
                Pair.of(null, Card.BLUE_WIZARD),
                Pair.of(null, Card.BLUE_JESTER),
                Pair.of(null, Card.GREEN_11)
        );
        assertEquals(Card.Suit.RED, CardUtils.getTrickSuit(stack));
    }

    @Test
    public void getTickSuit_ReturnsNone_IfFirstCardIsWizard() {
        List<Pair<UUID, Card>> stack = List.of(
                Pair.of(null, Card.BLUE_WIZARD),
                Pair.of(null, Card.RED_1),
                Pair.of(null, Card.YELLOW_1),
                Pair.of(null, Card.BLUE_JESTER),
                Pair.of(null, Card.GREEN_11)
        );
        assertEquals(Card.Suit.NONE, CardUtils.getTrickSuit(stack));
    }

    @Test
    public void getTrickSuit_IgnoresJesters() {
        List<Pair<UUID, Card>> stack = List.of(
                Pair.of(null, Card.BLUE_JESTER),
                Pair.of(null, Card.BLUE_WIZARD),
                Pair.of(null, Card.RED_1),
                Pair.of(null, Card.YELLOW_1),
                Pair.of(null, Card.GREEN_11)
        );
        assertEquals(Card.Suit.NONE, CardUtils.getTrickSuit(stack));

        List<Pair<UUID, Card>> stack2 = List.of(
                Pair.of(null, Card.BLUE_JESTER),
                Pair.of(null, Card.YELLOW_1),
                Pair.of(null, Card.BLUE_WIZARD),
                Pair.of(null, Card.RED_1),
                Pair.of(null, Card.GREEN_11)
        );
        assertEquals(Card.Suit.YELLOW, CardUtils.getTrickSuit(stack2));
    }
}
