package dbdata

import (
	"crypto/x509"
	"encoding/pem"
	"fmt"
	"testing"

	"github.com/bjdgyc/anylink/base"
	"github.com/stretchr/testify/assert"
)

func TestGenerateClientCert(t *testing.T) {
	base.Test()
	ast := assert.New(t)

	// 设置临时目录用于测试
	tempDir := t.TempDir()
	base.Cfg.ClientCertCAFile = tempDir + "/client_ca.pem"
	base.Cfg.ClientCertCAKeyFile = tempDir + "/client_ca_key.pem"

	preIpData()
	defer closeIpdata()

	// 使用 GenerateClientCA 生成 CA
	err := GenerateClientCA()
	ast.Nil(err, "生成客户端 CA 失败")

	// 创建测试组
	group := "cert-test-group"
	dns := []ValData{{Val: "8.8.8.8"}}
	g := Group{Name: group, Status: 1, ClientDns: dns}
	err = SetGroup(&g)
	ast.Nil(err)

	// 创建测试用户
	username := "cert-test-user"
	u := User{Username: username, Groups: []string{group}, Status: 1}
	err = SetUser(&u)
	ast.Nil(err)

	// 测试证书生成成功
	certData, err := GenerateClientCert(username, group)
	ast.Nil(err)
	ast.NotNil(certData)
	ast.Equal(username, certData.Username)
	ast.Equal(group, certData.Groupname)
	ast.Equal(CertStatusActive, certData.Status)
	ast.NotEmpty(certData.Certificate)
	ast.NotEmpty(certData.PrivateKey)
	ast.NotEmpty(certData.SerialNumber)

	// 测试重复生成证书失败
	_, err = GenerateClientCert(username, group)
	ast.NotNil(err)
	ast.Contains(err.Error(), "已存在证书")

	// 测试用户不属于指定组
	_, err = GenerateClientCert(username, "nonexistent-group")
	ast.NotNil(err)
	ast.Contains(err.Error(), "不属于组")

	// 测试用户不存在
	_, err = GenerateClientCert("nonexistent-user", group)
	ast.NotNil(err)
	ast.Contains(err.Error(), "用户不存在")
}
func TestCertificateAuthFlow(t *testing.T) {
	base.Test()
	ast := assert.New(t)

	preIpData()
	defer closeIpdata()

	// 设置测试环境
	group := "auth-test-group"
	username := "auth-test-user"

	// 创建组和用户
	dns := []ValData{{Val: "8.8.8.8"}}
	g := Group{Name: group, Status: 1, ClientDns: dns}
	err := SetGroup(&g)
	ast.Nil(err)

	u := User{Username: username, Groups: []string{group}, Status: 1}
	err = SetUser(&u)
	ast.Nil(err)

	// 生成证书
	certData, err := GenerateClientCert(username, group)
	ast.Nil(err)

	// 解析证书
	cert, err := parseCertFromPEM(certData.Certificate)
	ast.Nil(err)

	// 证书验证
	valid := ValidateClientCert(cert, "test-agent")
	ast.True(valid)

	// 测试证书状态变更
	certData.Status = CertStatusDisabled
	err = certData.UpdateStatus(CertStatusDisabled)
	ast.Nil(err)

	valid = ValidateClientCert(cert, "test-agent")
	ast.False(valid)
}

func TestValidateClientCert(t *testing.T) {
	base.Test()
	ast := assert.New(t)

	// 设置临时目录用于测试
	tempDir := t.TempDir()
	base.Cfg.ClientCertCAFile = tempDir + "/client_ca.pem"
	base.Cfg.ClientCertCAKeyFile = tempDir + "/client_ca_key.pem"

	preIpData()
	defer closeIpdata()

	// 初始化客户端 CA
	err := GenerateClientCA()
	ast.Nil(err, "初始化客户端 CA 失败")

	// 创建测试组
	group := "test-group"
	dns := []ValData{{Val: "8.8.8.8"}}
	g := Group{Name: group, Status: 1, ClientDns: dns}
	err = SetGroup(&g)
	ast.Nil(err)

	// 创建测试用户
	username := "test-user"
	u := User{Username: username, Groups: []string{group}, Status: 1}
	err = SetUser(&u)
	ast.Nil(err)

	// 生成客户端证书
	certData, err := GenerateClientCert(username, group)
	ast.Nil(err)
	ast.NotNil(certData)
	ast.Equal(username, certData.Username)
	ast.Equal(group, certData.Groupname)

	// 解析生成的证书
	cert, err := parseCertFromPEM(certData.Certificate)
	ast.Nil(err)
	ast.Equal(username, cert.Subject.CommonName)
	ast.Equal(group, cert.Subject.OrganizationalUnit[0])

	// 测试证书验证成功
	valid := ValidateClientCert(cert, "test-agent")
	ast.True(valid)

	// 测试用户不存在的情况
	cert.Subject.CommonName = "nonexistent-user"
	valid = ValidateClientCert(cert, "test-agent")
	ast.False(valid)

	// 测试用户被禁用的情况
	cert.Subject.CommonName = username
	u.Status = 0
	err = SetUser(&u)
	ast.Nil(err)
	valid = ValidateClientCert(cert, "test-agent")
	ast.False(valid)

	// 恢复用户状态
	u.Status = 1
	err = SetUser(&u)
	ast.Nil(err)

	// 测试证书组不匹配的情况
	cert.Subject.OrganizationalUnit[0] = "wrong-group"
	valid = ValidateClientCert(cert, "test-agent")
	ast.False(valid)

	// 测试证书状态被禁用的情况
	cert.Subject.OrganizationalUnit[0] = group
	certData.Status = CertStatusDisabled
	err = certData.Save()
	ast.Nil(err)
	valid = ValidateClientCert(cert, "test-agent")
	ast.False(valid)
}

func parseCertFromPEM(certPEM string) (*x509.Certificate, error) {
	block, _ := pem.Decode([]byte(certPEM))
	if block == nil {
		return nil, fmt.Errorf("failed to decode PEM block")
	}
	return x509.ParseCertificate(block.Bytes)
}
