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

#include "poker.h"

void test_pokerInit_should_InitializePokerGame(void) {
  poker_t poker;
  pokerInit(&poker);
  TEST_ASSERT_EQUAL_UINT8(0, poker.playerCount);
  TEST_ASSERT_EQUAL_UINT8(0, poker.playerDealer);
  TEST_ASSERT_EQUAL_UINT8(0, poker.playerSmallBlind);
  TEST_ASSERT_EQUAL_UINT8(0, poker.playerBigBlind);
}

void test_pokerResetRound_should_ResetTheRound(void) {
  poker_t poker;
  pokerInit(&poker);
  
  poker.potCount = 0x03;
  poker.graveSize = 0x10;
  poker.communitySize = 0x03;
  poker.deckSize = 0x0;

  pokerResetRound(&poker);

  TEST_ASSERT_NOT_EQUAL_UINT8(0, poker.deckSize);
  TEST_ASSERT_EQUAL_UINT8(0, poker.graveSize);
  TEST_ASSERT_EQUAL_UINT8(0, poker.communitySize);
  TEST_ASSERT_EQUAL_UINT8(1, poker.potCount);
}

void test_pokerResetRound_should_ResetThePlayers(void) {
  poker_t poker;
  uint8_t i;
  pokerInit(&poker);

  pokerPlayerAdd(&poker);
  pokerPlayerAdd(&poker);
  pokerPlayerAdd(&poker);


  for(i = 0; i < poker.playerCount; i++) {
    poker.players[i].cardCount = 32;
    poker.players[i].chips = 100;
    poker.players[i].state = 0xFF;
    poker.players[i].currentBet = 12345;
  };

  pokerResetRound(&poker);

  for(i = 0; i < poker.playerCount; i++) {
    TEST_ASSERT_EQUAL_UINT8(0, poker.players[i].cardCount);
    TEST_ASSERT_EQUAL_UINT8(0, poker.players[i].timesRaised);
    TEST_ASSERT_EQUAL_INT32(0, poker.players[i].currentBet);
    TEST_ASSERT_EQUAL_INT32(100, poker.players[i].chips);
    TEST_ASSERT_BITS_LOW(POKER_PLAYER_STATE_FOLDED, poker.players[i].state);
    TEST_ASSERT_BITS_LOW(
      POKER_PLAYER_STATE_HAS_BET_THIS_ROUND, poker.players[i].state
    );
    TEST_ASSERT_BITS_LOW(POKER_PLAYER_STATE_SHOWING, poker.players[i].state);
  }
}

void test_pokerResetBettingRound_should_ResetTheBettingRound(void) {
  poker_t poker;
  uint8_t i;

  pokerInit(&poker);
  poker.better = 0x32;
  pokerPlayerAdd(&poker);
  pokerPlayerAdd(&poker);
  pokerPlayerAdd(&poker);

  for(i = 0; i < poker.playerCount; i++) {
    pokerPlayerChipsAdd(poker.players + i, 1000);
  };

  pokerResetBettingRound(&poker);
  TEST_ASSERT_EQUAL_UINT8(0x01, poker.better);

  for(i = 0; i < poker.playerCount; i++) {
    TEST_ASSERT_BITS_LOW(
      POKER_PLAYER_STATE_HAS_BET_THIS_ROUND, poker.players[i].state
    );
  }
}

void test_pokerTakeBlinds_should_TakeTheBlinds(void) {
  poker_t poker;
  pokerInit(&poker);
  pokerSetBlinds(&poker, 100, 200);

  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);

  pokerDealerNew(&poker);

  TEST_ASSERT_EQUAL_INT32(1000, (poker.players + 0)->chips);
  TEST_ASSERT_EQUAL_INT32(1000, (poker.players + 1)->chips);
  TEST_ASSERT_EQUAL_INT32(1000, (poker.players + 2)->chips);
  TEST_ASSERT_EQUAL_INT32(1000, (poker.players + 3)->chips);
  TEST_ASSERT_EQUAL_INT32(1000, (poker.players + 4)->chips);

  pokerTakeBlinds(&poker);

  TEST_ASSERT_EQUAL_INT32(1000, (poker.players + 0)->chips);
  TEST_ASSERT_EQUAL_INT32(1000, (poker.players + 1)->chips);
  TEST_ASSERT_EQUAL_INT32(900, (poker.players + 2)->chips);
  TEST_ASSERT_EQUAL_INT32(800, (poker.players + 3)->chips);
  TEST_ASSERT_EQUAL_INT32(1000, (poker.players + 4)->chips);
  
  pokerDealerNew(&poker);
  pokerTakeBlinds(&poker);

  TEST_ASSERT_EQUAL_INT32(1000, (poker.players + 0)->chips);
  TEST_ASSERT_EQUAL_INT32(1000, (poker.players + 1)->chips);
  TEST_ASSERT_EQUAL_INT32(900, (poker.players + 2)->chips);
  TEST_ASSERT_EQUAL_INT32(700, (poker.players + 3)->chips);
  TEST_ASSERT_EQUAL_INT32(800, (poker.players + 4)->chips);
}

void test_pokerTakeBlinds_should_NotCountAsBetting(void) {
  poker_t poker;
  pokerInit(&poker);
  pokerSetBlinds(&poker, 100, 200);

  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);

  pokerDealerNew(&poker);

  TEST_ASSERT_BIT_LOW(
    POKER_PLAYER_STATE_HAS_BET_THIS_ROUND, poker.players[0].state
  );
  TEST_ASSERT_BIT_LOW(
    POKER_PLAYER_STATE_HAS_BET_THIS_ROUND, poker.players[1].state
  );
  TEST_ASSERT_BIT_LOW(
    POKER_PLAYER_STATE_HAS_BET_THIS_ROUND, poker.players[2].state
  );
  TEST_ASSERT_BIT_LOW(
    POKER_PLAYER_STATE_HAS_BET_THIS_ROUND, poker.players[3].state
  );
  TEST_ASSERT_BIT_LOW(
    POKER_PLAYER_STATE_HAS_BET_THIS_ROUND, poker.players[4].state
  );

  pokerTakeBlinds(&poker);

  TEST_ASSERT_BIT_LOW(
    POKER_PLAYER_STATE_HAS_BET_THIS_ROUND, poker.players[0].state
  );
  TEST_ASSERT_BIT_LOW(
    POKER_PLAYER_STATE_HAS_BET_THIS_ROUND, poker.players[1].state
  );
  TEST_ASSERT_BIT_LOW(
    POKER_PLAYER_STATE_HAS_BET_THIS_ROUND, poker.players[2].state
  );
  TEST_ASSERT_BIT_LOW(
    POKER_PLAYER_STATE_HAS_BET_THIS_ROUND, poker.players[3].state
  );
  TEST_ASSERT_BIT_LOW(
    POKER_PLAYER_STATE_HAS_BET_THIS_ROUND, poker.players[4].state
  );
}

void test_pokerPlayerGetCallBet_should_GetCallBet(void) {
  poker_t poker;
  uint8_t p0, p1, p2;

  pokerInit(&poker);
  p0 = pokerPlayerAdd(&poker);
  p1 = pokerPlayerAdd(&poker);
  p2 = pokerPlayerAdd(&poker);

  pokerBetForPlayer(&poker, p0, 100);
  TEST_ASSERT_EQUAL_INT32(0, pokerPlayerGetCallBet(&poker,poker.players+p0));
  TEST_ASSERT_EQUAL_INT32(100, pokerPlayerGetCallBet(&poker,poker.players+p1));
  TEST_ASSERT_EQUAL_INT32(100, pokerPlayerGetCallBet(&poker,poker.players+p2));

  pokerBetForPlayer(&poker, p1, 200);
  TEST_ASSERT_EQUAL_INT32(100, pokerPlayerGetCallBet(&poker,poker.players+p0));
  TEST_ASSERT_EQUAL_INT32(0, pokerPlayerGetCallBet(&poker,poker.players+p1));
  TEST_ASSERT_EQUAL_INT32(200, pokerPlayerGetCallBet(&poker,poker.players+p2));

  pokerBetForPlayer(&poker, p2, 300);
  TEST_ASSERT_EQUAL_INT32(200, pokerPlayerGetCallBet(&poker,poker.players+p0));
  TEST_ASSERT_EQUAL_INT32(100, pokerPlayerGetCallBet(&poker,poker.players+p1));
  TEST_ASSERT_EQUAL_INT32(0, pokerPlayerGetCallBet(&poker,poker.players+p2));
}

void test_pokerInRoundGetCount_should_ReturnCountOfPlayersInRound(void) {
  poker_t poker;
  uint8_t p0, p1, p2;

  pokerInit(&poker);
  p0 = pokerPlayerAdd(&poker);
  p1 = pokerPlayerAdd(&poker);
  p2 = pokerPlayerAdd(&poker);

  TEST_ASSERT_EQUAL_UINT8(0x00, pokerInRoundGetCount(&poker));

  pokerPlayerChipsAdd(poker.players + p0, 10000);
  TEST_ASSERT_EQUAL_UINT8(0x01, pokerInRoundGetCount(&poker));
  pokerPlayerChipsAdd(poker.players + p1, 10000);
  TEST_ASSERT_EQUAL_UINT8(0x02, pokerInRoundGetCount(&poker));
  pokerPlayerChipsAdd(poker.players + p2, 10000);
  TEST_ASSERT_EQUAL_UINT8(0x03, pokerInRoundGetCount(&poker));

  poker.players[0].state |= POKER_PLAYER_STATE_FOLDED;
  TEST_ASSERT_EQUAL_UINT8(0x02, pokerInRoundGetCount(&poker));
  poker.players[1].state |= POKER_PLAYER_STATE_FOLDED;
  TEST_ASSERT_EQUAL_UINT8(0x01, pokerInRoundGetCount(&poker));
  poker.players[2].state |= POKER_PLAYER_STATE_OUT;
  TEST_ASSERT_EQUAL_UINT8(0x00, pokerInRoundGetCount(&poker));
}

int test_poker_h() {
  UNITY_BEGIN();

  RUN_TEST(test_pokerInit_should_InitializePokerGame);
  RUN_TEST(test_pokerResetRound_should_ResetTheRound);
  RUN_TEST(test_pokerResetRound_should_ResetThePlayers);
  RUN_TEST(test_pokerResetBettingRound_should_ResetTheBettingRound);
  RUN_TEST(test_pokerTakeBlinds_should_TakeTheBlinds);
  RUN_TEST(test_pokerPlayerGetCallBet_should_GetCallBet);
  RUN_TEST(test_pokerTakeBlinds_should_NotCountAsBetting);
  RUN_TEST(test_pokerInRoundGetCount_should_ReturnCountOfPlayersInRound);

  return UNITY_END();
}