package cards

import "testing"

func TestNewDeck_IsAFullShoe(t *testing.T) {
	d := NewDeck(6)
	if len(d) != 312 {
		t.Fatalf("six decks hold %d cards, want 312", len(d))
	}
	seen := map[Card]int{}
	for _, c := range d {
		seen[c]++
	}
	if len(seen) != 52 {
		t.Fatalf("%d distinct cards, want 52", len(seen))
	}
	for c, n := range seen {
		if n != 6 {
			t.Fatalf("%s appears %d times in a six-deck shoe, want 6", c, n)
		}
	}
}

func TestNewDeck_ClampsToAtLeastOne(t *testing.T) {
	if len(NewDeck(0)) != 52 {
		t.Fatal("a zero-deck shoe should still hold one deck")
	}
}

func TestShuffle_SameSeedSameOrder(t *testing.T) {
	a, b := NewDeck(1), NewDeck(1)
	a.Shuffle(NewRNG(99, 1))
	b.Shuffle(NewRNG(99, 1))
	for i := range a {
		if a[i] != b[i] {
			t.Fatalf("same seed diverged at %d: %s vs %s", i, a[i], b[i])
		}
	}
	// And a different seed must not give the same order, or the RNG isn't wired up.
	c := NewDeck(1)
	c.Shuffle(NewRNG(100, 1))
	same := true
	for i := range a {
		if a[i] != c[i] {
			same = false
			break
		}
	}
	if same {
		t.Fatal("a different seed produced an identical shuffle")
	}
}

func TestShuffle_KeepsEveryCard(t *testing.T) {
	d := NewDeck(1)
	d.Shuffle(NewRNG(4, 4))
	seen := map[Card]bool{}
	for _, c := range d {
		seen[c] = true
	}
	if len(d) != 52 || len(seen) != 52 {
		t.Fatalf("shuffle lost cards: %d cards, %d distinct", len(d), len(seen))
	}
}

func TestDraw_TakesFromTheTopAndRunsOut(t *testing.T) {
	d := NewDeck(1)
	top := d[0]
	c, ok := d.Draw()
	if !ok || c != top {
		t.Fatalf("drew %s (ok=%v), want the top card %s", c, ok, top)
	}
	if len(d) != 51 {
		t.Fatalf("deck has %d cards after one draw, want 51", len(d))
	}
	for len(d) > 0 {
		d.Draw()
	}
	if _, ok := d.Draw(); ok {
		t.Fatal("an empty deck kept dealing")
	}
}

func TestCard_String(t *testing.T) {
	tests := []struct {
		card Card
		want string
	}{
		{Card{Ace, Spades}, "A♠"},
		{Card{10, Hearts}, "10♥"},
		{Card{King, Clubs}, "K♣"},
		{Card{Rank: 99, Suit: Spades}, "??"},
	}
	for _, tc := range tests {
		if got := tc.card.String(); got != tc.want {
			t.Errorf("String() = %q, want %q", got, tc.want)
		}
	}
	if !(Card{Ace, Hearts}).Red() || (Card{Ace, Spades}).Red() {
		t.Error("Red() disagrees about which suits are red")
	}
}
