package helper

import (
	"strings"
	"testing"
)

func TestCalculateSHA256(t *testing.T) {
	testCases := []struct {
		name     string
		input    string
		expected string
	}{
		{
			name:     "Simple string",
			input:    "hello",
			expected: "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824",
		},
		{
			name:     "Empty string",
			input:    "",
			expected: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
		},
		{
			name:     "String with spaces",
			input:    "hello world",
			expected: "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9",
		},
		{
			name:     "Numeric string",
			input:    "12345",
			expected: "5994471abb01112afcc18159f6cc74b4f511b99806da59b3caf5a9c173cacfc5",
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			result := CalculateSHA256(tc.input)
			if result != tc.expected {
				t.Errorf("Expected %s, got %s", tc.expected, result)
			}

			// Verify it's always 64 characters (SHA256 hex)
			if len(result) != 64 {
				t.Errorf("Expected 64 character hash, got %d", len(result))
			}
		})
	}
}

func TestCalculateSHA256FromBytes(t *testing.T) {
	testCases := []struct {
		name     string
		input    []byte
		expected string
	}{
		{
			name:     "Byte array",
			input:    []byte("test data"),
			expected: "916f0027a575074ce72a331777c3478d6513f786a591bd892da1a577bf2335f9",
		},
		{
			name:     "Empty byte array",
			input:    []byte{},
			expected: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
		},
		{
			name:     "Binary data",
			input:    []byte{0x00, 0x01, 0x02, 0xFF},
			expected: "3d1f57c984978ef98a18378c8166c1cb8ede02c03eeb6aee7e2f121dfeee3e56",
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			result := CalculateSHA256FromBytes(tc.input)
			if result != tc.expected {
				t.Errorf("Expected %s, got %s", tc.expected, result)
			}

			if len(result) != 64 {
				t.Errorf("Expected 64 character hash, got %d", len(result))
			}
		})
	}
}

func TestSha256(t *testing.T) {
	testCases := []struct {
		name  string
		input string
	}{
		{"Simple", "password123"},
		{"Empty", ""},
		{"Complex", "P@ssw0rd!#$%^&*()"},
		{"Unicode", "こんにちは"},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			result := Sha256(tc.input)

			// Should return 64 character hex string
			if len(result) != 64 {
				t.Errorf("Expected 64 character hash, got %d", len(result))
			}

			// Should be lowercase hex
			if result != strings.ToLower(result) {
				t.Error("Expected lowercase hex string")
			}

			// Should be deterministic
			result2 := Sha256(tc.input)
			if result != result2 {
				t.Error("Hash should be deterministic")
			}
		})
	}
}

func TestSHA256Consistency(t *testing.T) {
	input := "test consistency"

	// All three functions should produce the same hash for the same input
	hash1 := CalculateSHA256(input)
	hash2 := CalculateSHA256FromBytes([]byte(input))
	hash3 := Sha256(input)

	if hash1 != hash2 {
		t.Errorf("CalculateSHA256 and CalculateSHA256FromBytes produced different results: %s vs %s", hash1, hash2)
	}

	if hash1 != hash3 {
		t.Errorf("CalculateSHA256 and Sha256 produced different results: %s vs %s", hash1, hash3)
	}
}

func TestSHA256Uniqueness(t *testing.T) {
	inputs := []string{
		"password1",
		"password2",
		"password3",
		"different",
		"unique",
	}

	hashes := make(map[string]bool)

	for _, input := range inputs {
		hash := CalculateSHA256(input)

		if hashes[hash] {
			t.Errorf("Collision detected for input: %s", input)
		}

		hashes[hash] = true
	}
}

func TestSHA256LongInput(t *testing.T) {
	// Test with very long input
	longInput := strings.Repeat("a", 10000)
	hash := CalculateSHA256(longInput)

	if len(hash) != 64 {
		t.Errorf("Expected 64 character hash for long input, got %d", len(hash))
	}

	// Hash should be different from short input
	shortHash := CalculateSHA256("a")
	if hash == shortHash {
		t.Error("Long and short inputs should produce different hashes")
	}
}

func TestSHA256SpecialCharacters(t *testing.T) {
	specialInputs := []string{
		"\n\r\t",
		"spaces   everywhere",
		"!@#$%^&*()_+-=[]{}|;':\",./<>?",
		"emoji 🔐🔑",
	}

	for _, input := range specialInputs {
		hash := CalculateSHA256(input)

		if len(hash) != 64 {
			t.Errorf("Expected 64 character hash for input %q, got %d", input, len(hash))
		}

		// Should be valid hex
		for _, char := range hash {
			if !((char >= '0' && char <= '9') || (char >= 'a' && char <= 'f')) {
				t.Errorf("Invalid hex character %c in hash", char)
			}
		}
	}
}

func BenchmarkCalculateSHA256(b *testing.B) {
	input := "benchmark test string"
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		CalculateSHA256(input)
	}
}

func BenchmarkCalculateSHA256FromBytes(b *testing.B) {
	input := []byte("benchmark test string")
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		CalculateSHA256FromBytes(input)
	}
}

func BenchmarkSha256(b *testing.B) {
	input := "benchmark test string"
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		Sha256(input)
	}
}
