// ssl_test.go - SSL/TLS 客户端证书变量测试
//
// 测试覆盖：
//   - mTLS 客户端证书变量获取
//   - SetSSLClientInfoInContext 设置功能
//   - calculateFingerprint 指纹计算
//
// 作者：xfy
package variable

import (
	"testing"

	"github.com/valyala/fasthttp"
)

// TestGetSSLClientVerify_NilContext 测试 nil 上下文
func TestGetSSLClientVerify_NilContext(t *testing.T) {
	result := GetSSLClientVerify(nil)
	if result != "NONE" {
		t.Errorf("GetSSLClientVerify(nil) = %q, want NONE", result)
	}
}

// TestGetSSLClientVerify_NoTLS 测试非 TLS 连接
func TestGetSSLClientVerify_NoTLS(t *testing.T) {
	ctx := &fasthttp.RequestCtx{}
	// 默认情况下 IsTLS() 返回 false
	result := GetSSLClientVerify(ctx)
	if result != "NONE" {
		t.Errorf("GetSSLClientVerify(non-TLS) = %q, want NONE", result)
	}
}

// TestGetSSLClientVerify_NonTLSWithUserValue 测试非 TLS 连接即使设置了 UserValue 也返回 NONE
// 注意：GetSSLClientVerify 会先检查 ctx.IsTLS()，非 TLS 连接直接返回 NONE
// 这是正确的行为，SSL 客户端变量只在 TLS 连接中有效
func TestGetSSLClientVerify_NonTLSWithUserValue(t *testing.T) {
	ctx := &fasthttp.RequestCtx{}
	ctx.SetUserValue(VarSSLClientVerify, "SUCCESS")

	// 非 TLS 连接，即使设置了 UserValue 也应该返回 NONE
	result := GetSSLClientVerify(ctx)
	if result != "NONE" {
		t.Errorf("GetSSLClientVerify(non-TLS with value) = %q, want NONE", result)
	}
}

// TestGetSSLClientVerify_PeerCertPresent_NonTLS 测试非 TLS 下 peer_cert_present 不生效
func TestGetSSLClientVerify_PeerCertPresent_NonTLS(t *testing.T) {
	ctx := &fasthttp.RequestCtx{}
	ctx.SetUserValue("tls_peer_cert_present", true)

	// 非 TLS 连接，peer_cert_present 不应该改变结果
	result := GetSSLClientVerify(ctx)
	if result != "NONE" {
		t.Errorf("GetSSLClientVerify(non-TLS with peer_cert) = %q, want NONE", result)
	}
}

// TestGetSSLClientSerial 测试获取序列号
func TestGetSSLClientSerial(t *testing.T) {
	tests := []struct {
		name     string
		setup    func(*fasthttp.RequestCtx)
		expected string
	}{
		{
			name:     "no value",
			setup:    func(_ *fasthttp.RequestCtx) {},
			expected: "",
		},
		{
			name: "with serial",
			setup: func(ctx *fasthttp.RequestCtx) {
				ctx.SetUserValue(VarSSLClientSerial, "1234567890ABCDEF")
			},
			expected: "1234567890ABCDEF",
		},
		{
			name: "invalid type",
			setup: func(ctx *fasthttp.RequestCtx) {
				ctx.SetUserValue(VarSSLClientSerial, 12345)
			},
			expected: "",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			ctx := &fasthttp.RequestCtx{}
			tt.setup(ctx)
			result := GetSSLClientSerial(ctx)
			if result != tt.expected {
				t.Errorf("GetSSLClientSerial() = %q, want %q", result, tt.expected)
			}
		})
	}
}

// TestGetSSLClientSubject 测试获取主题
func TestGetSSLClientSubject(t *testing.T) {
	tests := []struct {
		name     string
		setup    func(*fasthttp.RequestCtx)
		expected string
	}{
		{
			name:     "no value",
			setup:    func(_ *fasthttp.RequestCtx) {},
			expected: "",
		},
		{
			name: "with subject",
			setup: func(ctx *fasthttp.RequestCtx) {
				ctx.SetUserValue(VarSSLClientSubject, "CN=test.example.com,O=Test Org")
			},
			expected: "CN=test.example.com,O=Test Org",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			ctx := &fasthttp.RequestCtx{}
			tt.setup(ctx)
			result := GetSSLClientSubject(ctx)
			if result != tt.expected {
				t.Errorf("GetSSLClientSubject() = %q, want %q", result, tt.expected)
			}
		})
	}
}

// TestGetSSLClientIssuer 测试获取颁发者
func TestGetSSLClientIssuer(t *testing.T) {
	tests := []struct {
		name     string
		setup    func(*fasthttp.RequestCtx)
		expected string
	}{
		{
			name:     "no value",
			setup:    func(_ *fasthttp.RequestCtx) {},
			expected: "",
		},
		{
			name: "with issuer",
			setup: func(ctx *fasthttp.RequestCtx) {
				ctx.SetUserValue(VarSSLClientIssuer, "CN=Test CA,O=Test Org")
			},
			expected: "CN=Test CA,O=Test Org",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			ctx := &fasthttp.RequestCtx{}
			tt.setup(ctx)
			result := GetSSLClientIssuer(ctx)
			if result != tt.expected {
				t.Errorf("GetSSLClientIssuer() = %q, want %q", result, tt.expected)
			}
		})
	}
}

// TestGetSSLClientFingerprint 测试获取指纹
func TestGetSSLClientFingerprint(t *testing.T) {
	tests := []struct {
		name     string
		setup    func(*fasthttp.RequestCtx)
		expected string
	}{
		{
			name:     "no value",
			setup:    func(_ *fasthttp.RequestCtx) {},
			expected: "",
		},
		{
			name: "with fingerprint",
			setup: func(ctx *fasthttp.RequestCtx) {
				ctx.SetUserValue(VarSSLClientFingerprint, "A1B2C3D4E5F6")
			},
			expected: "A1B2C3D4E5F6",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			ctx := &fasthttp.RequestCtx{}
			tt.setup(ctx)
			result := GetSSLClientFingerprint(ctx)
			if result != tt.expected {
				t.Errorf("GetSSLClientFingerprint() = %q, want %q", result, tt.expected)
			}
		})
	}
}

// TestGetSSLClientNotBefore 测试获取生效时间
func TestGetSSLClientNotBefore(t *testing.T) {
	tests := []struct {
		name     string
		setup    func(*fasthttp.RequestCtx)
		expected string
	}{
		{
			name:     "no value",
			setup:    func(_ *fasthttp.RequestCtx) {},
			expected: "",
		},
		{
			name: "with notbefore",
			setup: func(ctx *fasthttp.RequestCtx) {
				ctx.SetUserValue(VarSSLClientNotBefore, "2025-01-01T00:00:00Z")
			},
			expected: "2025-01-01T00:00:00Z",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			ctx := &fasthttp.RequestCtx{}
			tt.setup(ctx)
			result := GetSSLClientNotBefore(ctx)
			if result != tt.expected {
				t.Errorf("GetSSLClientNotBefore() = %q, want %q", result, tt.expected)
			}
		})
	}
}

// TestGetSSLClientNotAfter 测试获取过期时间
func TestGetSSLClientNotAfter(t *testing.T) {
	tests := []struct {
		name     string
		setup    func(*fasthttp.RequestCtx)
		expected string
	}{
		{
			name:     "no value",
			setup:    func(_ *fasthttp.RequestCtx) {},
			expected: "",
		},
		{
			name: "with notafter",
			setup: func(ctx *fasthttp.RequestCtx) {
				ctx.SetUserValue(VarSSLClientNotAfter, "2026-01-01T00:00:00Z")
			},
			expected: "2026-01-01T00:00:00Z",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			ctx := &fasthttp.RequestCtx{}
			tt.setup(ctx)
			result := GetSSLClientNotAfter(ctx)
			if result != tt.expected {
				t.Errorf("GetSSLClientNotAfter() = %q, want %q", result, tt.expected)
			}
		})
	}
}

// TestGetSSLClientEmail 测试获取邮箱
func TestGetSSLClientEmail(t *testing.T) {
	tests := []struct {
		name     string
		setup    func(*fasthttp.RequestCtx)
		expected string
	}{
		{
			name:     "no value",
			setup:    func(_ *fasthttp.RequestCtx) {},
			expected: "",
		},
		{
			name: "with email",
			setup: func(ctx *fasthttp.RequestCtx) {
				ctx.SetUserValue(VarSSLClientEmail, "test@example.com")
			},
			expected: "test@example.com",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			ctx := &fasthttp.RequestCtx{}
			tt.setup(ctx)
			result := GetSSLClientEmail(ctx)
			if result != tt.expected {
				t.Errorf("GetSSLClientEmail() = %q, want %q", result, tt.expected)
			}
		})
	}
}

// TestSSLVariablesInContext 测试通过 VariableContext 访问 SSL 变量
// 注意：ssl_client_verify 在非 TLS 连接下会返回 NONE（因为 GetSSLClientVerify 检查 ctx.IsTLS()）
func TestSSLVariablesInContext(t *testing.T) {
	ctx := &fasthttp.RequestCtx{}

	// 设置 SSL 客户端信息
	ctx.SetUserValue(VarSSLClientSerial, "ABC123")
	ctx.SetUserValue(VarSSLClientSubject, "CN=test")
	ctx.SetUserValue(VarSSLClientIssuer, "CN=CA")
	ctx.SetUserValue(VarSSLClientFingerprint, "FINGERPRINT")
	ctx.SetUserValue(VarSSLClientNotBefore, "2025-01-01T00:00:00Z")
	ctx.SetUserValue(VarSSLClientNotAfter, "2026-01-01T00:00:00Z")
	ctx.SetUserValue(VarSSLClientEmail, "test@example.com")

	vc := NewContext(ctx)
	defer ReleaseContext(vc)

	tests := []struct {
		varName  string
		expected string
	}{
		{VarSSLClientSerial, "ABC123"},
		{VarSSLClientSubject, "CN=test"},
		{VarSSLClientIssuer, "CN=CA"},
		{VarSSLClientFingerprint, "FINGERPRINT"},
		{VarSSLClientNotBefore, "2025-01-01T00:00:00Z"},
		{VarSSLClientNotAfter, "2026-01-01T00:00:00Z"},
		{VarSSLClientEmail, "test@example.com"},
	}

	for _, tt := range tests {
		t.Run(tt.varName, func(t *testing.T) {
			value, ok := vc.Get(tt.varName)
			if !ok {
				t.Errorf("variable %s not found", tt.varName)
				return
			}
			if value != tt.expected {
				t.Errorf("%s = %q, want %q", tt.varName, value, tt.expected)
			}
		})
	}
}

// TestSSLVariablesInContext_VerifyNonTLS 测试 ssl_client_verify 在非 TLS 下返回 NONE
func TestSSLVariablesInContext_VerifyNonTLS(t *testing.T) {
	ctx := &fasthttp.RequestCtx{}
	ctx.SetUserValue(VarSSLClientVerify, "SUCCESS")

	vc := NewContext(ctx)
	defer ReleaseContext(vc)

	// 非 TLS 连接，ssl_client_verify 应该返回 NONE
	value, ok := vc.Get(VarSSLClientVerify)
	if !ok {
		t.Error("ssl_client_verify not found")
		return
	}
	if value != "NONE" {
		t.Errorf("ssl_client_verify = %q, want NONE (non-TLS context)", value)
	}
}

// TestSSLVariablesExpand 测试在模板中展开 SSL 变量
// 注意：ssl_client_verify 在非 TLS 连接下会返回 NONE
func TestSSLVariablesExpand(t *testing.T) {
	ctx := &fasthttp.RequestCtx{}

	ctx.SetUserValue(VarSSLClientSerial, "12345")
	ctx.SetUserValue(VarSSLClientSubject, "CN=test")

	vc := NewContext(ctx)
	defer ReleaseContext(vc)

	tests := []struct {
		template string
		expected string
	}{
		{"$ssl_client_serial", "12345"},
		{"$ssl_client_subject", "CN=test"},
		{"serial=$ssl_client_serial subject=$ssl_client_subject", "serial=12345 subject=CN=test"},
	}

	for _, tt := range tests {
		t.Run(tt.template, func(t *testing.T) {
			result := vc.Expand(tt.template)
			if result != tt.expected {
				t.Errorf("Expand(%q) = %q, want %q", tt.template, result, tt.expected)
			}
		})
	}
}

// TestSSLVariablesExpand_VerifyNonTLS 测试 ssl_client_verify 在非 TLS 下展开为 NONE
func TestSSLVariablesExpand_VerifyNonTLS(t *testing.T) {
	ctx := &fasthttp.RequestCtx{}
	ctx.SetUserValue(VarSSLClientVerify, "SUCCESS")

	vc := NewContext(ctx)
	defer ReleaseContext(vc)

	// 非 TLS 连接，ssl_client_verify 应该展开为 NONE
	result := vc.Expand("$ssl_client_verify")
	if result != "NONE" {
		t.Errorf("Expand($ssl_client_verify) = %q, want NONE (non-TLS context)", result)
	}
}
