package identity

import (
	"bytes"
	"path/filepath"
	"testing"
)

func TestNewIdentity(t *testing.T) {
	id, err := New()
	if err != nil {
		t.Fatalf("New() failed: %v", err)
	}
	if id == nil {
		t.Fatal("New() returned nil")
	}

	pubKey := id.GetPublicKey()
	if len(pubKey) != 64 {
		t.Errorf("Expected public key length 64, got %d", len(pubKey))
	}

	privKey := id.GetPrivateKey()
	if len(privKey) != 64 {
		t.Errorf("Expected private key length 64, got %d", len(privKey))
	}
}

func TestSignVerify(t *testing.T) {
	id, _ := New()
	data := []byte("test data")
	sig := id.Sign(data)

	if !id.Verify(data, sig) {
		t.Error("Verification failed for valid signature")
	}

	if id.Verify([]byte("wrong data"), sig) {
		t.Error("Verification succeeded for wrong data")
	}
}

func TestEncryptDecrypt(t *testing.T) {
	id, _ := New()
	plaintext := []byte("secret message")

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

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

	if !bytes.Equal(plaintext, decrypted) {
		t.Errorf("Decrypted data doesn't match plaintext: %q vs %q", decrypted, plaintext)
	}
}

func TestIdentityHash(t *testing.T) {
	id, _ := New()
	h := id.Hash()
	if len(h) != TRUNCATED_HASHLENGTH/8 {
		t.Errorf("Expected hash length %d, got %d", TRUNCATED_HASHLENGTH/8, len(h))
	}

	hexHash := id.Hex()
	if len(hexHash) != TRUNCATED_HASHLENGTH/4 {
		t.Errorf("Expected hex hash length %d, got %d", TRUNCATED_HASHLENGTH/4, len(hexHash))
	}
}

func TestFileOperations(t *testing.T) {
	tmpDir := t.TempDir()
	idPath := filepath.Join(tmpDir, "identity")

	id, _ := New()
	err := id.ToFile(idPath)
	if err != nil {
		t.Fatalf("ToFile failed: %v", err)
	}

	loadedID, err := FromFile(idPath)
	if err != nil {
		t.Fatalf("FromFile failed: %v", err)
	}

	if !bytes.Equal(id.GetPublicKey(), loadedID.GetPublicKey()) {
		t.Error("Loaded identity public key doesn't match original")
	}
}

func TestRatchets(t *testing.T) {
	id, _ := New()

	ratchet, err := id.RotateRatchet()
	if err != nil {
		t.Fatalf("RotateRatchet failed: %v", err)
	}
	if len(ratchet) != RATCHETSIZE/8 {
		t.Errorf("Expected ratchet size %d, got %d", RATCHETSIZE/8, len(ratchet))
	}

	ratchets := id.GetRatchets()
	if len(ratchets) != 1 {
		t.Errorf("Expected 1 ratchet, got %d", len(ratchets))
	}

	id.CleanupExpiredRatchets()
	// Should still be there since it's not expired
	if len(id.GetRatchets()) != 1 {
		t.Error("Ratchet unexpectedly cleaned up")
	}
}

func TestRecallIdentity(t *testing.T) {
	tmpDir := t.TempDir()
	idPath := filepath.Join(tmpDir, "identity_recall")

	id, _ := New()
	_ = id.ToFile(idPath)

	recalledID, err := RecallIdentity(idPath)
	if err != nil {
		t.Fatalf("RecallIdentity failed: %v", err)
	}

	if !bytes.Equal(id.GetPublicKey(), recalledID.GetPublicKey()) {
		t.Error("Recalled identity public key doesn't match original")
	}
}

func TestTruncatedHash(t *testing.T) {
	data := []byte("some data")
	h := TruncatedHash(data)
	if len(h) != TRUNCATED_HASHLENGTH/8 {
		t.Errorf("Expected length %d, got %d", TRUNCATED_HASHLENGTH/8, len(h))
	}
}

func TestGetRandomHash(t *testing.T) {
	h := GetRandomHash()
	if len(h) != TRUNCATED_HASHLENGTH/8 {
		t.Errorf("Expected length %d, got %d", TRUNCATED_HASHLENGTH/8, len(h))
	}
}
