import { PlayingCard, Deck, Suit } from "../src";
import { InvalidArgumentError, OutOfBoundsError } from "../src/errors";

let deck: Deck;
describe("Testing the addCard, drawCard and cardCount functions: ", () => {
  test("Return value is a Deck object and card is added: ", () => {
    deck = new Deck();
    expect(deck.addCard(new PlayingCard("A", Suit.clubs)).count).toBe(1);
    const card = deck.drawCard();
    expect(card.getRank()).toBe("A");
    expect((card as PlayingCard).getSuit()).toBe(Suit.clubs);
  });
});

describe("Testing deck creation: ", () => {
  test("Check the size of each created deck: ", () => {
    expect(Deck.generateDeck().count).toBe(52);
    expect(Deck.generateStandardDeck().count).toBe(52);
    expect(Deck.generatePiquetDeck().count).toBe(32);
    expect(Deck.generateSpanishDeck().count).toBe(48);
    expect(Deck.generate500Deck(2).count).toBe(43);
    expect(Deck.generate500Deck(3).count).toBe(33);
    expect(Deck.generate500Deck(4).count).toBe(43);
    expect(Deck.generate500Deck(5).count).toBe(53);
    expect(Deck.generate500Deck(6).count).toBe(63);
  });
  test("Ensure incorrect 500 Deck generation throws appropriate error: ", () => {
    expect(() => Deck.generate500Deck(1)).toThrowError(
      new InvalidArgumentError("Arguement must be a number between 2 and 6, inclusive.")
    );
    expect(() => Deck.generate500Deck(7)).toThrowError(
      new InvalidArgumentError("Arguement must be a number between 2 and 6, inclusive.")
    );
    expect(() => new Deck().drawCard()).toThrowError(
      new OutOfBoundsError("There are no cards available to draw from the deck.")
    );
  });
});

describe("Testing the removeCard function: ", () => {
  test("Check the count has been reduced after using removeCard: ", () => {
    deck = Deck.generateDeck();
    expect(deck.removeCard(new PlayingCard("4", Suit.diamonds)).count).toBe(51);
  });
});

describe("Testing the validateDeck function: ", () => {
  deck = Deck.generateDeck();
  test("Check known validated deck to be valid: ", () => {
    expect(deck.validateDeck()).toBe(true);
  });
  test("Check known invalid deck to be invalid: ", () => {
    deck.addCard(new PlayingCard("A", Suit.spades));
    expect(deck.validateDeck()).toBe(false);
  });
});
