package crypto

import (
	"testing"
)

func TestDeriveKey(t *testing.T) {
	key := DeriveKey("test-passphrase-that-is-long-enough")
	if key == [32]byte{} {
		t.Fatal("DeriveKey returned zero key")
	}
	// Same input produces same output
	key2 := DeriveKey("test-passphrase-that-is-long-enough")
	if key != key2 {
		t.Fatal("DeriveKey is not deterministic")
	}
	// Different input produces different output
	key3 := DeriveKey("different-passphrase-also-long-enough")
	if key == key3 {
		t.Fatal("DeriveKey produced same key for different inputs")
	}
}

func TestEncryptDecryptRoundTrip(t *testing.T) {
	key := DeriveKey("test-key-for-encryption-testing-1234")
	plaintext := "super-secret-value"

	encrypted, err := Encrypt(key, plaintext)
	if err != nil {
		t.Fatalf("Encrypt failed: %v", err)
	}
	if encrypted == plaintext {
		t.Fatal("Encrypt returned plaintext")
	}
	if encrypted == "" {
		t.Fatal("Encrypt returned empty string")
	}

	decrypted, err := Decrypt(key, encrypted)
	if err != nil {
		t.Fatalf("Decrypt failed: %v", err)
	}
	if decrypted != plaintext {
		t.Fatalf("Decrypt mismatch: got %q, want %q", decrypted, plaintext)
	}
}

func TestDecryptWithWrongKey(t *testing.T) {
	key1 := DeriveKey("key-one-for-testing-encryption-1234")
	key2 := DeriveKey("key-two-for-testing-encryption-5678")

	encrypted, err := Encrypt(key1, "secret")
	if err != nil {
		t.Fatalf("Encrypt failed: %v", err)
	}

	_, err = Decrypt(key2, encrypted)
	if err == nil {
		t.Fatal("Decrypt with wrong key should have failed")
	}
}

func TestEncryptIfNotEmpty(t *testing.T) {
	key := DeriveKey("test-key-for-encryption-testing-1234")

	result, err := EncryptIfNotEmpty(key, "")
	if err != nil {
		t.Fatalf("EncryptIfNotEmpty with empty input failed: %v", err)
	}
	if result != "" {
		t.Fatal("EncryptIfNotEmpty should return empty for empty input")
	}

	result, err = EncryptIfNotEmpty(key, "value")
	if err != nil {
		t.Fatalf("EncryptIfNotEmpty failed: %v", err)
	}
	if result == "" || result == "value" {
		t.Fatal("EncryptIfNotEmpty should encrypt non-empty input")
	}
}

func TestKeyFromEnv(t *testing.T) {
	// Test with no key set
	t.Setenv("ENCRYPTION_KEY", "")
	_, err := KeyFromEnv()
	if err == nil {
		t.Fatal("KeyFromEnv should fail with empty ENCRYPTION_KEY")
	}

	// Test with valid key
	t.Setenv("ENCRYPTION_KEY", "a-very-long-encryption-key-that-is-definitely-over-32-chars")
	key, err := KeyFromEnv()
	if err != nil {
		t.Fatalf("KeyFromEnv failed with valid key: %v", err)
	}
	if key == [32]byte{} {
		t.Fatal("KeyFromEnv returned zero key")
	}
}

func TestEncryptProducesDifferentCiphertexts(t *testing.T) {
	key := DeriveKey("test-key-for-nonce-uniqueness-1234")

	enc1, err := Encrypt(key, "same-plaintext")
	if err != nil {
		t.Fatalf("Encrypt 1 failed: %v", err)
	}

	enc2, err := Encrypt(key, "same-plaintext")
	if err != nil {
		t.Fatalf("Encrypt 2 failed: %v", err)
	}

	if enc1 == enc2 {
		t.Fatal("Two encryptions of the same plaintext should produce different ciphertexts (random nonce)")
	}
}

func TestDecryptInvalidHex(t *testing.T) {
	key := DeriveKey("test-key-for-invalid-hex-testing")

	_, err := Decrypt(key, "not-valid-hex!!!")
	if err == nil {
		t.Fatal("Decrypt should fail with invalid hex input")
	}
}

func TestDecryptTooShort(t *testing.T) {
	key := DeriveKey("test-key-for-short-ciphertext-test")

	_, err := Decrypt(key, "aabb")
	if err == nil {
		t.Fatal("Decrypt should fail with ciphertext shorter than nonce")
	}
}
