package md5

import (
	"fmt"
	"os"
	"testing"
)

func TestEncryptString(t *testing.T) {
	tests := []struct {
		input    string
		expected string
	}{
		{"", "d41d8cd98f00b204e9800998ecf8427e"},
		{"hello", "5d41402abc4b2a76b9719d911017c592"},
		{"123456", "e10adc3949ba59abbe56e057f20f883e"},
		{"Hello World!", "ed076287532e86365e841e92bfc50d8c"},
	}

	for _, test := range tests {
		result := EncryptString(test.input)
		fmt.Println(result)
		if result != test.expected {
			t.Errorf("EncryptString(%s) = %s; want %s", test.input, result, test.expected)
		}
	}
}

func TestEncryptBytes(t *testing.T) {
	tests := []struct {
		input    []byte
		expected string
	}{
		{[]byte(""), "d41d8cd98f00b204e9800998ecf8427e"},
		{[]byte("hello"), "5d41402abc4b2a76b9719d911017c592"},
		{[]byte{0, 1, 2, 3, 4}, "5267768822ee624d48fce15ec5ca79b6"},
	}

	for _, test := range tests {
		result := EncryptBytes(test.input)
		if result != test.expected {
			t.Errorf("EncryptBytes(%v) = %s; want %s", test.input, result, test.expected)
		}
	}
}

func TestMD5Chain(t *testing.T) {
	// 测试链式调用
	result := New().
		Add("hello").
		Add(" ").
		Add("world").
		Sum()

	expected := "fc5e038d38a57032085441e7fe7010b0" // MD5("hello world")
	if result != expected {
		t.Errorf("Chain MD5 = %s; want %s", result, expected)
	}

	// 测试从字符串初始化
	result = FromString("hello").Add(" world").Sum()
	if result != expected {
		t.Errorf("FromString MD5 = %s; want %s", result, expected)
	}

	// 测试从字节切片初始化
	result = FromBytes([]byte("hello")).AddBytes([]byte(" world")).Sum()
	if result != expected {
		t.Errorf("FromBytes MD5 = %s; want %s", result, expected)
	}
}

func TestVerifyMD5(t *testing.T) {
	if !VerifyMD5("hello", "5d41402abc4b2a76b9719d911017c592") {
		t.Error("VerifyMD5 failed for correct match")
	}

	if VerifyMD5("hello", "wrong-hash") {
		t.Error("VerifyMD5 succeeded for incorrect match")
	}

	// 测试大小写不敏感
	if !VerifyMD5("hello", "5D41402ABC4B2A76B9719D911017C592") {
		t.Error("VerifyMD5 failed for uppercase hash")
	}
}

func TestSaltAndPrefix(t *testing.T) {
	// 测试加盐
	saltResult := EncryptStringWithSalt("password", "salt123")
	expectedSalt := EncryptString("passwordsalt123")
	if saltResult != expectedSalt {
		t.Errorf("EncryptStringWithSalt = %s; want %s", saltResult, expectedSalt)
	}

	// 测试前缀
	prefixResult := EncryptStringWithPrefix("password", "prefix123")
	expectedPrefix := EncryptString("prefix123password")
	if prefixResult != expectedPrefix {
		t.Errorf("EncryptStringWithPrefix = %s; want %s", prefixResult, expectedPrefix)
	}

	// 验证带盐值的MD5
	if !VerifyMD5WithSalt("password", "salt123", saltResult) {
		t.Error("VerifyMD5WithSalt failed for correct match")
	}
}

func TestGet16And8(t *testing.T) {
	full := EncryptString("test-string")

	// 测试16位MD5
	result16 := Get16("test-string")
	expected16 := full[8:24]
	if result16 != expected16 {
		t.Errorf("Get16 = %s; want %s", result16, expected16)
	}

	// 测试8位MD5
	result8 := Get8("test-string")
	expected8 := full[12:20]
	if result8 != expected8 {
		t.Errorf("Get8 = %s; want %s", result8, expected8)
	}
}

func TestMD5HMAC(t *testing.T) {
	// 已知的HMAC-MD5结果
	tests := []struct {
		message  string
		key      string
		expected string
	}{
		{"message", "key", "4e4748e62b463521f6775fbf921234b5"},
		{"test", "secret", "8b11d99898918564dda1a9fe205b5310"},
	}

	for _, test := range tests {
		result := MD5HMAC(test.message, test.key)
		if result != test.expected {
			t.Errorf("MD5HMAC(%s, %s) = %s; want %s",
				test.message, test.key, result, test.expected)
		}
	}
}

func TestEncryptFile(t *testing.T) {
	// 创建临时测试文件
	content := []byte("test file content for MD5")
	tmpFile, err := os.CreateTemp("", "md5test-*.txt")
	if err != nil {
		t.Fatalf("无法创建临时文件: %v", err)
	}
	defer os.Remove(tmpFile.Name())

	if _, err := tmpFile.Write(content); err != nil {
		t.Fatalf("无法写入临时文件: %v", err)
	}
	if err := tmpFile.Close(); err != nil {
		t.Fatalf("无法关闭临时文件: %v", err)
	}

	// 计算文件MD5
	fileHash, err := EncryptFile(tmpFile.Name())
	if err != nil {
		t.Fatalf("计算文件MD5失败: %v", err)
	}

	// 验证文件MD5
	expectedHash := EncryptBytes(content)
	if fileHash != expectedHash {
		t.Errorf("文件MD5 = %s; 应为 %s", fileHash, expectedHash)
	}

	// 测试VerifyFileMD5
	match, err := VerifyFileMD5(tmpFile.Name(), expectedHash)
	if err != nil {
		t.Fatalf("验证文件MD5失败: %v", err)
	}
	if !match {
		t.Error("VerifyFileMD5返回false，应返回true")
	}

	// 测试不匹配的情况
	match, err = VerifyFileMD5(tmpFile.Name(), "wronghash")
	if err != nil {
		t.Fatalf("验证文件MD5失败: %v", err)
	}
	if match {
		t.Error("VerifyFileMD5对错误的哈希返回true，应返回false")
	}
}
