package services

import (
	"bytes"
	"crypto/rand"
	"encoding/hex"
	"testing"
)

// validTestKey returns a deterministic 64-char hex key for tests.
func validTestKey() string {
	return "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
}

// randomHexKey generates a random 64-char hex key.
func randomHexKey(t *testing.T) string {
	t.Helper()
	b := make([]byte, 32)
	if _, err := rand.Read(b); err != nil {
		t.Fatal(err)
	}
	return hex.EncodeToString(b)
}

func TestNewEncryptionService_Valid(t *testing.T) {
	svc, err := NewEncryptionService(validTestKey())
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if svc == nil {
		t.Fatal("expected non-nil service")
	}
}

func TestNewEncryptionService_InvalidHex(t *testing.T) {
	// 64 chars but not valid hex
	_, err := NewEncryptionService("zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz")
	if err == nil {
		t.Fatal("expected error for invalid hex")
	}
}

func TestNewEncryptionService_WrongLength(t *testing.T) {
	tests := []struct {
		name string
		key  string
	}{
		{"too short", "0123456789abcdef"},
		{"too long", "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef00"},
		{"empty", ""},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			_, err := NewEncryptionService(tt.key)
			if err == nil {
				t.Fatal("expected error for wrong length key")
			}
		})
	}
}

func TestEncryptDecrypt_RoundTrip(t *testing.T) {
	svc, err := NewEncryptionService(validTestKey())
	if err != nil {
		t.Fatal(err)
	}

	plaintext := []byte("Hello, encryption at rest!")

	ciphertext, err := svc.Encrypt(plaintext)
	if err != nil {
		t.Fatalf("encrypt failed: %v", err)
	}

	decrypted, err := svc.Decrypt(ciphertext)
	if err != nil {
		t.Fatalf("decrypt failed: %v", err)
	}

	if !bytes.Equal(plaintext, decrypted) {
		t.Fatalf("round-trip mismatch: got %q, want %q", decrypted, plaintext)
	}
}

func TestEncryptDecrypt_EmptyPlaintext(t *testing.T) {
	svc, err := NewEncryptionService(validTestKey())
	if err != nil {
		t.Fatal(err)
	}

	ciphertext, err := svc.Encrypt([]byte{})
	if err != nil {
		t.Fatalf("encrypt failed: %v", err)
	}

	decrypted, err := svc.Decrypt(ciphertext)
	if err != nil {
		t.Fatalf("decrypt failed: %v", err)
	}

	if len(decrypted) != 0 {
		t.Fatalf("expected empty plaintext, got %d bytes", len(decrypted))
	}
}

func TestEncrypt_DifferentCiphertexts(t *testing.T) {
	svc, err := NewEncryptionService(validTestKey())
	if err != nil {
		t.Fatal(err)
	}

	plaintext := []byte("same input")
	ct1, err := svc.Encrypt(plaintext)
	if err != nil {
		t.Fatal(err)
	}
	ct2, err := svc.Encrypt(plaintext)
	if err != nil {
		t.Fatal(err)
	}

	if bytes.Equal(ct1, ct2) {
		t.Fatal("encrypting the same plaintext twice should produce different ciphertexts")
	}
}

func TestDecrypt_TamperDetection(t *testing.T) {
	svc, err := NewEncryptionService(validTestKey())
	if err != nil {
		t.Fatal(err)
	}

	ciphertext, err := svc.Encrypt([]byte("sensitive data"))
	if err != nil {
		t.Fatal(err)
	}

	// Flip a byte near the end (in the ciphertext portion)
	tampered := make([]byte, len(ciphertext))
	copy(tampered, ciphertext)
	tampered[len(tampered)-1] ^= 0xFF

	_, err = svc.Decrypt(tampered)
	if err == nil {
		t.Fatal("expected error when decrypting tampered ciphertext")
	}
}

func TestDecrypt_WrongKEK(t *testing.T) {
	svc1, err := NewEncryptionService(validTestKey())
	if err != nil {
		t.Fatal(err)
	}

	ciphertext, err := svc1.Encrypt([]byte("secret"))
	if err != nil {
		t.Fatal(err)
	}

	// Create a second service with a different key
	svc2, err := NewEncryptionService(randomHexKey(t))
	if err != nil {
		t.Fatal(err)
	}

	_, err = svc2.Decrypt(ciphertext)
	if err == nil {
		t.Fatal("expected error when decrypting with wrong KEK")
	}
}

func TestDecrypt_TooShort(t *testing.T) {
	svc, err := NewEncryptionService(validTestKey())
	if err != nil {
		t.Fatal(err)
	}

	_, err = svc.Decrypt([]byte("short"))
	if err == nil {
		t.Fatal("expected error for too-short ciphertext")
	}
}

func TestDecrypt_BadVersion(t *testing.T) {
	svc, err := NewEncryptionService(validTestKey())
	if err != nil {
		t.Fatal(err)
	}

	ciphertext, err := svc.Encrypt([]byte("data"))
	if err != nil {
		t.Fatal(err)
	}

	// Change version byte
	ciphertext[0] = 0xFF

	_, err = svc.Decrypt(ciphertext)
	if err == nil {
		t.Fatal("expected error for bad version")
	}
}

func TestIsEnabled(t *testing.T) {
	svc, err := NewEncryptionService(validTestKey())
	if err != nil {
		t.Fatal(err)
	}

	if !svc.IsEnabled() {
		t.Fatal("expected IsEnabled() to return true")
	}

	var nilSvc *EncryptionService
	if nilSvc.IsEnabled() {
		t.Fatal("expected IsEnabled() to return false for nil service")
	}
}
