package crypto

import (
	"bytes"
	"crypto/rand"
	"strings"
	"testing"
)

func testKey(t *testing.T) []byte {
	t.Helper()
	key := make([]byte, 32)
	if _, err := rand.Read(key); err != nil {
		t.Fatal(err)
	}
	return key
}

func TestSealOpenRoundTrip(t *testing.T) {
	key := testKey(t)
	tests := [][]byte{
		[]byte(`{"email":"a@b.c","apiToken":"secret-token"}`),
		[]byte(""),
		[]byte(strings.Repeat("x", 100000)),
		{0x00, 0xFF, 0x10},
	}
	for _, plaintext := range tests {
		sealed, err := Seal(key, plaintext)
		if err != nil {
			t.Fatalf("Seal: %v", err)
		}
		got, err := Open(key, sealed)
		if err != nil {
			t.Fatalf("Open: %v", err)
		}
		if !bytes.Equal(got, plaintext) {
			t.Errorf("round trip mismatch for %d-byte input", len(plaintext))
		}
	}
}

func TestSealIsNonDeterministic(t *testing.T) {
	key := testKey(t)
	a, _ := Seal(key, []byte("same"))
	b, _ := Seal(key, []byte("same"))
	if a == b {
		t.Fatal("two seals of the same plaintext must differ (random nonce)")
	}
}

func TestOpenRejectsTampering(t *testing.T) {
	key := testKey(t)
	sealed, err := Seal(key, []byte("credentials"))
	if err != nil {
		t.Fatal(err)
	}

	if _, err := Open(testKey(t), sealed); err == nil {
		t.Error("wrong key must fail")
	}
	if _, err := Open(key, "!!not-base64!!"); err == nil {
		t.Error("invalid base64 must fail")
	}
	if _, err := Open(key, "AAAA"); err == nil {
		t.Error("too-short ciphertext must fail")
	}
	corrupted := []byte(sealed)
	mid := len(corrupted) / 2
	if corrupted[mid] == 'A' {
		corrupted[mid] = 'B'
	} else {
		corrupted[mid] = 'A'
	}
	if _, err := Open(key, string(corrupted)); err == nil {
		t.Error("corrupted ciphertext must fail authentication")
	}
}

func TestKeyLengthEnforced(t *testing.T) {
	if _, err := Seal(make([]byte, 16), []byte("x")); err == nil {
		t.Error("16-byte key must be rejected")
	}
	if _, err := Open(make([]byte, 31), "AAAA"); err == nil {
		t.Error("31-byte key must be rejected")
	}
}
