/**
 * Copyright (c) 2021 Dominic Masters
 * 
 * This software is released under the MIT License.
 * https://opensource.org/licenses/MIT
 */

#include "dealer.h"

void test_pokerDealerSet_should_SetANewSetOfPlayers(void) {
  poker_t poker;
  pokerInit(&poker);

  pokerPlayerChipsAdd(poker.players + pokerPlayerAdd(&poker), 1000);
  pokerPlayerChipsAdd(poker.players + pokerPlayerAdd(&poker), 1000);
  pokerPlayerChipsAdd(poker.players + pokerPlayerAdd(&poker), 1000);
  pokerPlayerChipsAdd(poker.players + pokerPlayerAdd(&poker), 1000);
  pokerPlayerChipsAdd(poker.players + pokerPlayerAdd(&poker), 1000);
  
  pokerDealerSet(&poker, 0x00);
  TEST_ASSERT_EQUAL_UINT8(0, poker.playerDealer);
  TEST_ASSERT_EQUAL_UINT8(1, poker.playerSmallBlind);
  TEST_ASSERT_EQUAL_UINT8(2, poker.playerBigBlind);

  pokerDealerSet(&poker, 0x01);
  TEST_ASSERT_EQUAL_UINT8(1, poker.playerDealer);
  TEST_ASSERT_EQUAL_UINT8(2, poker.playerSmallBlind);
  TEST_ASSERT_EQUAL_UINT8(3, poker.playerBigBlind);

  pokerDealerSet(&poker, 0x02);
  TEST_ASSERT_EQUAL_UINT8(2, poker.playerDealer);
  TEST_ASSERT_EQUAL_UINT8(3, poker.playerSmallBlind);
  TEST_ASSERT_EQUAL_UINT8(4, poker.playerBigBlind);

  pokerDealerSet(&poker, 0x03);
  TEST_ASSERT_EQUAL_UINT8(3, poker.playerDealer);
  TEST_ASSERT_EQUAL_UINT8(4, poker.playerSmallBlind);
  TEST_ASSERT_EQUAL_UINT8(0, poker.playerBigBlind);

  pokerDealerSet(&poker, 0x04);
  TEST_ASSERT_EQUAL_UINT8(4, poker.playerDealer);
  TEST_ASSERT_EQUAL_UINT8(0, poker.playerSmallBlind);
  TEST_ASSERT_EQUAL_UINT8(1, poker.playerBigBlind);

  pokerDealerSet(&poker, 0x00);
  TEST_ASSERT_EQUAL_UINT8(0, poker.playerDealer);
  TEST_ASSERT_EQUAL_UINT8(1, poker.playerSmallBlind);
  TEST_ASSERT_EQUAL_UINT8(2, poker.playerBigBlind);
}

void test_pokerDealerSet_should_SkipOutPlayers(void) {
  poker_t poker;
  pokerInit(&poker);

  pokerPlayerChipsAdd(poker.players + pokerPlayerAdd(&poker), 1000);
  pokerPlayerChipsAdd(poker.players + pokerPlayerAdd(&poker), 1000);
  pokerPlayerAdd(&poker);
  pokerPlayerChipsAdd(poker.players + pokerPlayerAdd(&poker), 1000);
  pokerPlayerAdd(&poker);

  pokerDealerSet(&poker, 0x00);
  TEST_ASSERT_EQUAL_UINT8(0, poker.playerDealer);
  TEST_ASSERT_EQUAL_UINT8(1, poker.playerSmallBlind);
  TEST_ASSERT_EQUAL_UINT8(3, poker.playerBigBlind);
  
  pokerDealerSet(&poker, 0x01);
  TEST_ASSERT_EQUAL_UINT8(1, poker.playerDealer);
  TEST_ASSERT_EQUAL_UINT8(3, poker.playerSmallBlind);
  TEST_ASSERT_EQUAL_UINT8(0, poker.playerBigBlind);
  
  pokerDealerSet(&poker, 0x02);
  TEST_ASSERT_EQUAL_UINT8(3, poker.playerDealer);
  TEST_ASSERT_EQUAL_UINT8(0, poker.playerSmallBlind);
  TEST_ASSERT_EQUAL_UINT8(1, poker.playerBigBlind);

  pokerDealerSet(&poker, 0x03);
  TEST_ASSERT_EQUAL_UINT8(3, poker.playerDealer);
  TEST_ASSERT_EQUAL_UINT8(0, poker.playerSmallBlind);
  TEST_ASSERT_EQUAL_UINT8(1, poker.playerBigBlind);

  pokerDealerSet(&poker, 0x04);
  TEST_ASSERT_EQUAL_UINT8(0, poker.playerDealer);
  TEST_ASSERT_EQUAL_UINT8(1, poker.playerSmallBlind);
  TEST_ASSERT_EQUAL_UINT8(3, poker.playerBigBlind);
}

void test_pokerDealerNew_should_FindANewDealer(void) {
  poker_t poker;
  pokerInit(&poker);

  pokerPlayerChipsAdd(poker.players + pokerPlayerAdd(&poker), 1000);
  pokerPlayerChipsAdd(poker.players + pokerPlayerAdd(&poker), 1000);
  pokerPlayerChipsAdd(poker.players + pokerPlayerAdd(&poker), 1000);
  pokerPlayerChipsAdd(poker.players + pokerPlayerAdd(&poker), 1000);
  pokerPlayerChipsAdd(poker.players + pokerPlayerAdd(&poker), 1000);
  
  TEST_ASSERT_EQUAL_UINT8(0, poker.playerDealer);
  TEST_ASSERT_EQUAL_UINT8(0, poker.playerSmallBlind);
  TEST_ASSERT_EQUAL_UINT8(0, poker.playerBigBlind);

  pokerDealerNew(&poker);
  TEST_ASSERT_EQUAL_UINT8(1, poker.playerDealer);
  TEST_ASSERT_EQUAL_UINT8(2, poker.playerSmallBlind);
  TEST_ASSERT_EQUAL_UINT8(3, poker.playerBigBlind);

  pokerDealerNew(&poker);
  TEST_ASSERT_EQUAL_UINT8(2, poker.playerDealer);
  TEST_ASSERT_EQUAL_UINT8(3, poker.playerSmallBlind);
  TEST_ASSERT_EQUAL_UINT8(4, poker.playerBigBlind);

  pokerDealerNew(&poker);
  TEST_ASSERT_EQUAL_UINT8(3, poker.playerDealer);
  TEST_ASSERT_EQUAL_UINT8(4, poker.playerSmallBlind);
  TEST_ASSERT_EQUAL_UINT8(0, poker.playerBigBlind);

  pokerDealerNew(&poker);
  TEST_ASSERT_EQUAL_UINT8(4, poker.playerDealer);
  TEST_ASSERT_EQUAL_UINT8(0, poker.playerSmallBlind);
  TEST_ASSERT_EQUAL_UINT8(1, poker.playerBigBlind);
}

void test_pokerDealerTurn_should_TurnCardsFromTheDeck(void) {
  poker_t poker;
  pokerInit(&poker);

  TEST_ASSERT_EQUAL_UINT8(CARD_DECK_SIZE, poker.deckSize);
  TEST_ASSERT_EQUAL_UINT8(0, poker.communitySize);

  pokerDealerTurn(&poker, 1);
  TEST_ASSERT_EQUAL_UINT8(CARD_DECK_SIZE - 1, poker.deckSize);
  TEST_ASSERT_EQUAL_UINT8(1, poker.communitySize);
  TEST_ASSERT_EQUAL_UINT8(CARD_SPADES_ACE, poker.community[0]);

  pokerDealerTurn(&poker, 3);
  TEST_ASSERT_EQUAL_UINT8(CARD_DECK_SIZE - 4, poker.deckSize);
  TEST_ASSERT_EQUAL_UINT8(4, poker.communitySize);
  TEST_ASSERT_EQUAL_UINT8(CARD_SPADES_KING, poker.community[1]);
  TEST_ASSERT_EQUAL_UINT8(CARD_SPADES_QUEEN, poker.community[2]);
  TEST_ASSERT_EQUAL_UINT8(CARD_SPADES_JACK, poker.community[3]);
}

void test_pokerDealerBurn_should_SendCardsToTheGrave(void) {
  poker_t poker;
  pokerInit(&poker);

  TEST_ASSERT_EQUAL_UINT8(CARD_DECK_SIZE, poker.deckSize);
  TEST_ASSERT_EQUAL_UINT8(0, poker.graveSize);

  pokerDealerBurn(&poker, 1);
  TEST_ASSERT_EQUAL_UINT8(CARD_DECK_SIZE - 1, poker.deckSize);
  TEST_ASSERT_EQUAL_UINT8(1, poker.graveSize);
  TEST_ASSERT_EQUAL_UINT8(CARD_SPADES_ACE, poker.grave[0]);

  pokerDealerBurn(&poker, 3);
  TEST_ASSERT_EQUAL_UINT8(CARD_DECK_SIZE - 4, poker.deckSize);
  TEST_ASSERT_EQUAL_UINT8(4, poker.graveSize);
  TEST_ASSERT_EQUAL_UINT8(CARD_SPADES_KING, poker.grave[1]);
  TEST_ASSERT_EQUAL_UINT8(CARD_SPADES_QUEEN, poker.grave[2]);
  TEST_ASSERT_EQUAL_UINT8(CARD_SPADES_JACK, poker.grave[3]);

}

void test_pokerDeal_should_DealCardsToThePlayer(void) {
  poker_t poker;
  uint8_t playerIndex;
  pokerplayer_t *player;

  pokerInit(&poker);

  playerIndex = pokerPlayerAdd(&poker);
  player = poker.players + playerIndex;

  TEST_ASSERT_EQUAL_UINT8(CARD_DECK_SIZE, poker.deckSize);
  TEST_ASSERT_EQUAL_UINT8(0, player->cardCount);

  pokerDeal(&poker, player, 0x01);
  TEST_ASSERT_EQUAL_UINT8(CARD_DECK_SIZE - 1, poker.deckSize);
  TEST_ASSERT_EQUAL_UINT8(1, player->cardCount);
  TEST_ASSERT_EQUAL_UINT8(CARD_SPADES_ACE, player->cards[0]);

  pokerDeal(&poker, player, 0x01);
  TEST_ASSERT_EQUAL_UINT8(CARD_DECK_SIZE - 2, poker.deckSize);
  TEST_ASSERT_EQUAL_UINT8(2, player->cardCount);
  TEST_ASSERT_EQUAL_UINT8(CARD_SPADES_KING, player->cards[1]);
}

void test_pokerDealAllPlayers_should_DealCardsToEveryone(void) {
  poker_t poker;
  pokerInit(&poker);

  pokerPlayerChipsAdd(poker.players + pokerPlayerAdd(&poker), 100);
  pokerPlayerChipsAdd(poker.players + pokerPlayerAdd(&poker), 100);
  pokerPlayerChipsAdd(poker.players + pokerPlayerAdd(&poker), 100);

  TEST_ASSERT_EQUAL_UINT8(CARD_DECK_SIZE, poker.deckSize);
  TEST_ASSERT_EQUAL_UINT8(0, poker.players[0].cardCount);
  TEST_ASSERT_EQUAL_UINT8(0, poker.players[1].cardCount);
  TEST_ASSERT_EQUAL_UINT8(0, poker.players[2].cardCount);
  
  pokerDealAllPlayers(&poker, 1);
  TEST_ASSERT_EQUAL_UINT8(CARD_DECK_SIZE - 3, poker.deckSize);
  TEST_ASSERT_EQUAL_UINT8(1, poker.players[0].cardCount);
  TEST_ASSERT_EQUAL_UINT8(1, poker.players[1].cardCount);
  TEST_ASSERT_EQUAL_UINT8(1, poker.players[2].cardCount);
  
  TEST_ASSERT_EQUAL_UINT8(CARD_SPADES_ACE, poker.players[0].cards[0]);
  TEST_ASSERT_EQUAL_UINT8(CARD_SPADES_KING, poker.players[1].cards[0]);
  TEST_ASSERT_EQUAL_UINT8(CARD_SPADES_QUEEN, poker.players[2].cards[0]);
}

void test_pokerDealAllPlayers_should_DealMultipleCardsToEveryone(void) {
  poker_t poker;
  pokerInit(&poker);

  pokerPlayerChipsAdd(poker.players + pokerPlayerAdd(&poker), 100);
  pokerPlayerChipsAdd(poker.players + pokerPlayerAdd(&poker), 100);
  pokerPlayerChipsAdd(poker.players + pokerPlayerAdd(&poker), 100);

  TEST_ASSERT_EQUAL_UINT8(CARD_DECK_SIZE, poker.deckSize);
  TEST_ASSERT_EQUAL_UINT8(0, poker.players[0].cardCount);
  
  pokerDealAllPlayers(&poker, 0x02);
  TEST_ASSERT_EQUAL_UINT8(2, poker.players[0].cardCount);
  TEST_ASSERT_EQUAL_UINT8(2, poker.players[1].cardCount);
  TEST_ASSERT_EQUAL_UINT8(2, poker.players[2].cardCount);
  
  TEST_ASSERT_EQUAL_UINT8(CARD_SPADES_ACE, poker.players[0].cards[0]);
  TEST_ASSERT_EQUAL_UINT8(CARD_SPADES_KING, poker.players[1].cards[0]);
  TEST_ASSERT_EQUAL_UINT8(CARD_SPADES_QUEEN, poker.players[2].cards[0]);
  TEST_ASSERT_EQUAL_UINT8(CARD_SPADES_JACK, poker.players[0].cards[1]);
  TEST_ASSERT_EQUAL_UINT8(CARD_SPADES_TEN, poker.players[1].cards[1]);
  TEST_ASSERT_EQUAL_UINT8(CARD_SPADES_NINE, poker.players[2].cards[1]);
}

void test_pokerDealAllPlayers_should_NotDealToOutPlayers(void) {
  poker_t poker;
  pokerInit(&poker);

  pokerPlayerChipsAdd(poker.players + pokerPlayerAdd(&poker), 100);
  pokerPlayerAdd(&poker);
  pokerPlayerChipsAdd(poker.players + pokerPlayerAdd(&poker), 100);

  TEST_ASSERT_EQUAL_UINT8(CARD_DECK_SIZE, poker.deckSize);
  TEST_ASSERT_EQUAL_UINT8(0, poker.players[0].cardCount);
  
  pokerDealAllPlayers(&poker, 0x02);
  TEST_ASSERT_EQUAL_UINT8(2, poker.players[0].cardCount);
  TEST_ASSERT_EQUAL_UINT8(0, poker.players[1].cardCount);
  TEST_ASSERT_EQUAL_UINT8(2, poker.players[2].cardCount);
  
  TEST_ASSERT_EQUAL_UINT8(CARD_SPADES_ACE, poker.players[0].cards[0]);
  TEST_ASSERT_EQUAL_UINT8(CARD_SPADES_KING, poker.players[2].cards[0]);
  TEST_ASSERT_EQUAL_UINT8(CARD_SPADES_QUEEN, poker.players[0].cards[1]);
  TEST_ASSERT_EQUAL_UINT8(CARD_SPADES_JACK, poker.players[2].cards[1]);
}

void test_pokerDealAllPlayers_should_NotDealToFoldedPlayers(void) {
  poker_t poker;
  pokerInit(&poker);

  pokerPlayerChipsAdd(poker.players + pokerPlayerAdd(&poker), 100);
  pokerPlayerChipsAdd(poker.players + pokerPlayerAdd(&poker), 100);
  pokerPlayerChipsAdd(poker.players + pokerPlayerAdd(&poker), 100);
  poker.players[0].state |= POKER_PLAYER_STATE_FOLDED;

  pokerDealAllPlayers(&poker, 2);
  TEST_ASSERT_EQUAL_UINT8(0, poker.players[0].cardCount);
  TEST_ASSERT_EQUAL_UINT8(2, poker.players[1].cardCount);
  TEST_ASSERT_EQUAL_UINT8(2, poker.players[2].cardCount);
  
  TEST_ASSERT_EQUAL_UINT8(CARD_SPADES_ACE, poker.players[1].cards[0]);
  TEST_ASSERT_EQUAL_UINT8(CARD_SPADES_KING, poker.players[2].cards[0]);
  TEST_ASSERT_EQUAL_UINT8(CARD_SPADES_QUEEN, poker.players[1].cards[1]);
  TEST_ASSERT_EQUAL_UINT8(CARD_SPADES_JACK, poker.players[2].cards[1]);
}

int test_dealer_h() {
  UNITY_BEGIN();

  RUN_TEST(test_pokerDealerSet_should_SetANewSetOfPlayers);
  RUN_TEST(test_pokerDealerSet_should_SkipOutPlayers);
  RUN_TEST(test_pokerDealerNew_should_FindANewDealer);
  RUN_TEST(test_pokerDealerTurn_should_TurnCardsFromTheDeck);
  RUN_TEST(test_pokerDealerBurn_should_SendCardsToTheGrave);
  RUN_TEST(test_pokerDeal_should_DealCardsToThePlayer);
  RUN_TEST(test_pokerDealAllPlayers_should_DealCardsToEveryone);
  RUN_TEST(test_pokerDealAllPlayers_should_DealMultipleCardsToEveryone);
  RUN_TEST(test_pokerDealAllPlayers_should_NotDealToOutPlayers);
  RUN_TEST(test_pokerDealAllPlayers_should_NotDealToFoldedPlayers);

  return UNITY_END();
}