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

#pragma once
#include "../libs.h"
#include "../util/flags.h"
#include "card.h"

/** Maximum number of players that the game state can support */
#define POKER_PLAYER_COUNT_MAX 5

/** Maximum cards a players' hand can hold */
#define POKER_PLAYER_HAND_SIZE_MAX 2

/** Player States */
#define POKER_PLAYER_STATE_FOLDED flagDefine(0)
#define POKER_PLAYER_STATE_OUT flagDefine(1)
#define POKER_PLAYER_STATE_HAS_BET_THIS_ROUND flagDefine(2)
#define POKER_PLAYER_STATE_SHOWING flagDefine(3)

/** Maximum number of cards that the grave can hold */
#define POKER_GRAVE_SIZE_MAX CARD_DECK_SIZE

/** Maximum number of community cards */
#define POKER_COMMUNITY_SIZE_MAX 5

/** Maximum number of pots in the poker game. */
#define POKER_POT_COUNT_MAX POKER_PLAYER_COUNT_MAX

/** Maximum number of cards a winning state can hold. */
#define POKER_WINNING_FULL_SIZE (\
  POKER_PLAYER_HAND_SIZE_MAX + POKER_COMMUNITY_SIZE_MAX\
)

/** How many cards in the winning set */
#define POKER_WINNING_SET_SIZE 5

/** Winning Types */
#define POKER_WINNING_TYPE_NULL 0x00
#define POKER_WINNING_TYPE_ROYAL_FLUSH 0x01
#define POKER_WINNING_TYPE_STRAIGHT_FLUSH 0x02
#define POKER_WINNING_TYPE_FOUR_OF_A_KIND 0x03
#define POKER_WINNING_TYPE_FULL_HOUSE 0x04
#define POKER_WINNING_TYPE_FLUSH 0x05
#define POKER_WINNING_TYPE_STRAIGHT 0x06
#define POKER_WINNING_TYPE_THREE_OF_A_KIND 0x07
#define POKER_WINNING_TYPE_TWO_PAIR 0x08
#define POKER_WINNING_TYPE_PAIR 0x09
#define POKER_WINNING_TYPE_HIGH_CARD 0x0A

#define POKER_WINNING_CONFIDENCE_ROYAL_FLUSH 1.0f
#define POKER_WINNING_CONFIDENCE_STRAIGHT_FLUSH 0.99f
#define POKER_WINNING_CONFIDENCE_FOUR_OF_A_KIND 0.9f
#define POKER_WINNING_CONFIDENCE_FULL_HOUSE 0.85f
#define POKER_WINNING_CONFIDENCE_FLUSH 0.8f
#define POKER_WINNING_CONFIDENCE_STRAIGHT 0.7f
#define POKER_WINNING_CONFIDENCE_THREE_OF_A_KIND 0.5f
#define POKER_WINNING_CONFIDENCE_TWO_PAIR 0.4f
#define POKER_WINNING_CONFIDENCE_PAIR 0.2f
#define POKER_WINNING_CONFIDENCE_HIGH_CARD 0.1f

#define POKER_WORLD_DEALER_INDEX 0x02
#define POKER_WORLD_HUMAN_INDEX 0x02

/** Turn Types */
#define POKER_TURN_TYPE_OUT 0x00
#define POKER_TURN_TYPE_FOLD 0x01
#define POKER_TURN_TYPE_BET 0x02
#define POKER_TURN_TYPE_CALL 0x03
#define POKER_TURN_TYPE_ALL_IN 0x04
#define POKER_TURN_TYPE_CALL_ALL_IN 0x04
#define POKER_TURN_TYPE_CHECK 0x05

#define POKER_TURN_MAX_RAISES 0x02

/** How many chips each player has by defautl */
#define POKER_BET_PLAYER_CHIPS_DEFAULT 1200
/** The default blind cost for the big blind. */
#define POKER_BET_BLIND_BIG_DEFAULT 600
/** The default blind cost for the small blind. (Defaults half big blind) */
#define POKER_BET_BLIND_SMALL_DEFAULT (POKER_BET_BLIND_BIG_DEFAULT/2)

/** How many cards are dealt for the flop, turn and river */
#define POKER_FLOP_CARD_COUNT 3
#define POKER_TURN_CARD_COUNT 1
#define POKER_RIVER_CARD_COUNT 1

/** How many cards the dealer should burn before dealing the flop */
#define POKER_FLOP_BURN_COUNT 1

typedef struct {
  /** Count of chips the player has */
  int32_t chips;

  /** Cards in the players' hand */
  card_t cards[POKER_PLAYER_HAND_SIZE_MAX];
  uint8_t cardCount;

  /** Players current state */
  uint8_t state;

  /** Current bet that the player has done. */
  int32_t currentBet;

  /** Count of times that the player has raised their bet */
  uint8_t timesRaised;
} pokerplayer_t;

/** Holds information about a player's winning state */
typedef struct {
  /** The full set of both the dealer and player's hand */
  card_t full[POKER_WINNING_FULL_SIZE];
  uint8_t fullSize;
  
  /** Holds the winning set */
  card_t set[POKER_WINNING_SET_SIZE];
  uint8_t setSize;

  /** Winning Type */
  uint8_t type;

  /** If there was a kicker card it will be here, otherwise -1 for no kicker */
  card_t kicker;
} pokerplayerwinning_t;

typedef struct {
  /** Current pot of chips */
  int32_t chips;
  /** Current call value for this pot */
  int32_t call;
  /** Players who are participating in the pot */
  uint8_t players[POKER_PLAYER_COUNT_MAX];
  uint8_t playerCount;
} pokerpot_t;

typedef struct {
  /** What type of action the turn is */
  uint8_t type;
  /** How many chips they did in their turn (if applicable) */
  int32_t chips;
  /** How confident the AI is about their turn. 0 = none, 1 = full */
  float confidence;
} pokerturn_t;

typedef struct {
  /** Current Card Deck (Dealer) */
  card_t deck[CARD_DECK_SIZE];
  uint8_t deckSize;

  /** Card grave (where spent cards go when burned */
  card_t grave[POKER_GRAVE_SIZE_MAX];
  uint8_t graveSize;

  /** Dealer Hand */
  card_t community[POKER_COMMUNITY_SIZE_MAX];
  uint8_t communitySize;

  /** List of pots in the game (side pots) */
  pokerpot_t pots[POKER_POT_COUNT_MAX];
  uint8_t potCount;

  /** Players within the game */
  pokerplayer_t players[POKER_PLAYER_COUNT_MAX];
  uint8_t playerCount;

  /** Index of the dealer player */
  uint8_t playerDealer;
  /** Index of the small blind player */
  uint8_t playerSmallBlind;
  /** Index of the big blind player */
  uint8_t playerBigBlind;

  /** Which player is the current active better ? */
  uint8_t better;

  /** Size of the small blind */
  int32_t blindSmall;
  /** Size of the big blind */
  int32_t blindBig;
} poker_t;