package premium_dm

import (
	"encoding/base64"
	"encoding/json"
	"testing"

	dmconfig "github.com/pingcap/tiflow/dm/config"
	dmopenapi "github.com/pingcap/tiflow/dm/openapi"
	"github.com/stretchr/testify/require"
	"github.com/tidbcloud/dataflow-service-ng/app/repo/entity"
)

func TestBuildCreateSourceSecurityOmitsEmptyCertAllowedCn(t *testing.T) {
	security := buildCreateSourceSecurity(&entity.PremiumSecurity{
		SslCaContent:   []byte("ca"),
		SslCertContent: []byte("cert"),
		SslKeyContent:  []byte("key"),
	})

	require.NotNil(t, security)
	require.Nil(t, security.CertAllowedCn)

	password := "pwd"
	payload, err := json.Marshal(&dmopenapi.CreateSourceRequest{
		Source: dmopenapi.Source{
			Enable:     true,
			Host:       "127.0.0.1",
			Password:   &password,
			Port:       3306,
			SourceName: "source-1",
			Security:   security,
			User:       "root",
		},
	})
	require.NoError(t, err)
	require.NotContains(t, string(payload), `"cert_allowed_cn"`)
	require.NotContains(t, string(payload), `"cert_allowed_cn":null`)
}

func TestBuildCreateSourceSecurityKeepsNonEmptyCertAllowedCn(t *testing.T) {
	security := buildCreateSourceSecurity(&entity.PremiumSecurity{
		CertAllowedCn:  []string{"cn-a", "cn-b"},
		SslCaContent:   []byte("ca"),
		SslCertContent: []byte("cert"),
		SslKeyContent:  []byte("key"),
	})

	require.NotNil(t, security)
	require.NotNil(t, security.CertAllowedCn)
	require.Equal(t, []string{"cn-a", "cn-b"}, *security.CertAllowedCn)

	password := "pwd"
	payload, err := json.Marshal(&dmopenapi.CreateSourceRequest{
		Source: dmopenapi.Source{
			Enable:     true,
			Host:       "127.0.0.1",
			Password:   &password,
			Port:       3306,
			SourceName: "source-1",
			Security:   security,
			User:       "root",
		},
	})
	require.NoError(t, err)
	require.Contains(t, string(payload), `"cert_allowed_cn":["cn-a","cn-b"]`)
}

func TestTLSRegressionEmptyCertAllowedCnKeepsPrecheckSecurityAndOmitsCreateField(t *testing.T) {
	source := &entity.PremiumDMSource{
		ConnProfile: entity.PremiumConnProfile{
			Security: &entity.PremiumSecurity{
				SslCaContent:   []byte("ca"),
				SslCertContent: []byte("cert"),
				SslKeyContent:  []byte("key"),
			},
		},
	}

	precheckCfg := ApplyPremiumSourcePrecheckConfig(
		&dmconfig.SubTaskConfig{LoaderConfig: dmconfig.DefaultLoaderConfig()},
		source,
		entity.PremiumDMTaskModeAll,
		entity.PremiumDMTaskImportModeLogical,
	)
	require.NotNil(t, precheckCfg)
	require.NotNil(t, precheckCfg.From.Security)
	require.Equal(t, base64.StdEncoding.EncodeToString([]byte("ca")), precheckCfg.From.Security.SSLCABase64)
	require.Equal(t, base64.StdEncoding.EncodeToString([]byte("cert")), precheckCfg.From.Security.SSLCertBase64)
	require.Equal(t, base64.StdEncoding.EncodeToString([]byte("key")), precheckCfg.From.Security.SSLKeyBase64)

	createSecurity := buildCreateSourceSecurity(source.ConnProfile.Security)
	require.NotNil(t, createSecurity)
	require.Nil(t, createSecurity.CertAllowedCn)

	password := "pwd"
	payload, err := json.Marshal(&dmopenapi.CreateSourceRequest{
		Source: dmopenapi.Source{
			Enable:     true,
			Host:       "127.0.0.1",
			Password:   &password,
			Port:       3306,
			SourceName: "source-1",
			Security:   createSecurity,
			User:       "root",
		},
	})
	require.NoError(t, err)
	require.Contains(t, string(payload), `"ssl_ca_content":"ca"`)
	require.Contains(t, string(payload), `"ssl_cert_content":"cert"`)
	require.Contains(t, string(payload), `"ssl_key_content":"key"`)
	require.NotContains(t, string(payload), `"cert_allowed_cn":null`)
}

func TestTLSRegressionNonEmptyCertAllowedCnKeepsPrecheckAndCreateConfig(t *testing.T) {
	source := &entity.PremiumDMSource{
		ConnProfile: entity.PremiumConnProfile{
			Security: &entity.PremiumSecurity{
				CertAllowedCn:  []string{"cn-a", "cn-b"},
				SslCaContent:   []byte("ca"),
				SslCertContent: []byte("cert"),
				SslKeyContent:  []byte("key"),
			},
		},
	}

	precheckCfg := ApplyPremiumSourcePrecheckConfig(
		&dmconfig.SubTaskConfig{LoaderConfig: dmconfig.DefaultLoaderConfig()},
		source,
		entity.PremiumDMTaskModeAll,
		entity.PremiumDMTaskImportModeLogical,
	)
	require.NotNil(t, precheckCfg)
	require.NotNil(t, precheckCfg.From.Security)
	require.Equal(t, []string{"cn-a", "cn-b"}, []string(precheckCfg.From.Security.CertAllowedCN))

	createSecurity := buildCreateSourceSecurity(source.ConnProfile.Security)
	require.NotNil(t, createSecurity)
	require.NotNil(t, createSecurity.CertAllowedCn)
	require.Equal(t, []string{"cn-a", "cn-b"}, *createSecurity.CertAllowedCn)
}
