package cluster

import (
	"fmt"
	"os"
	"path"
	"testing"

	. "github.com/onsi/gomega"
	"github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1"
	operatorconfig "github.com/pingcap/tidb-operator/pkg/apis/util/config"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/testutil"
	"github.com/tidbcloud/config-service/pkg/metric"
)

var (
	versionV6x1x0 = "v6.1.0"
)

func TestAnalysisPlanAndRecordMetrics(t *testing.T) {
	clusterId := "1234"
	g := NewGomegaWithT(t)
	tc := makeTCData()

	type subCase struct {
		desc     string
		fixture  string
		dryRun   bool
		mutateFn func(tc *v1alpha1.TidbCluster)
	}

	cs := []subCase{
		subCase{
			desc:     "all default version changed",
			fixture:  "default_version_changed.metrics",
			dryRun:   true,
			mutateFn: changeDefaultVersion,
		},
		subCase{
			desc:     "change versions except tiflash",
			fixture:  "version_changed_except_tiflash.metrics",
			dryRun:   true,
			mutateFn: versionChangeExceptTiflash,
		},
		subCase{
			desc:     "changes tidb configs",
			fixture:  "change_tidb_configs.metrics",
			dryRun:   true,
			mutateFn: changeTiDBCfg,
		},
		subCase{
			desc:    "policy is not dryrun",
			fixture: "policy_not_dryrun.metrics",
			dryRun:  false,
		},
		subCase{
			desc:     "tiflash removed",
			fixture:  "tiflash_removed.metrics",
			dryRun:   true,
			mutateFn: removeTiflashComponent,
		},
	}

	for _, c := range cs {
		new := tc.DeepCopy()
		if c.mutateFn != nil {
			c.mutateFn(new)
		}
		analysisPlanAndRecordMetrics(tc, new, c.dryRun, clusterId)
		expectMetrics(g, metric.ConfigDryrunAffected, c.desc, c.fixture)
	}
}

func expectMetrics(g *WithT, c prometheus.Collector, desc string, fixture string) {
	exp, err := os.Open(path.Join("test", fixture))
	g.Expect(err).To(Succeed())
	err = testutil.CollectAndCompare(c, exp)
	g.Expect(err).Should(Succeed(), fmt.Sprintf("Unexpected metrics returned for case %s", desc))
}

func changeDefaultVersion(tc *v1alpha1.TidbCluster) {
	tc.Spec.Version = versionV6x1x0
	tc.Spec.PD.Version = &versionV6x1x0
	tc.Spec.TiDB.Version = &versionV6x1x0
	tc.Spec.TiKV.Version = &versionV6x1x0
	tc.Spec.TiFlash.Version = &versionV6x1x0
}

func changeTiDBCfg(tc *v1alpha1.TidbCluster) {
	tc.Spec.TiDB.Config.Set("log", map[string]string{"level": "info"})
}

func versionChangeExceptTiflash(tc *v1alpha1.TidbCluster) {
	tc.Spec.PD.Version = &versionV6x1x0
	tc.Spec.TiDB.Version = &versionV6x1x0
	tc.Spec.TiKV.Version = &versionV6x1x0
}

func removeTiflashComponent(tc *v1alpha1.TidbCluster) {
	tc.Spec.TiFlash = nil
}

func makeTCData() *v1alpha1.TidbCluster {
	version := "v5.3.1-20220303"
	pdCfg := v1alpha1.NewPDConfig()
	pdCfg.Set("log", map[string]string{"level": "debug"})
	tidbCfg := v1alpha1.NewTiDBConfig()
	tidbCfg.Set("log", map[string]string{"level": "debug"})
	tikvCfg := v1alpha1.NewTiKVConfig()
	tikvCfg.Set("log", map[string]string{"level": "debug"})
	return &v1alpha1.TidbCluster{
		Spec: v1alpha1.TidbClusterSpec{
			Version: version,
			PD: &v1alpha1.PDSpec{
				ComponentSpec: v1alpha1.ComponentSpec{
					Version:          &version,
					ImagePullPolicy:  nil,
					ImagePullSecrets: nil,
				},
				BaseImage: "pd",
				Config:    pdCfg,
			},
			TiDB: &v1alpha1.TiDBSpec{
				ComponentSpec: v1alpha1.ComponentSpec{
					Version:          &version,
					ImagePullPolicy:  nil,
					ImagePullSecrets: nil,
				},
				BaseImage: "tidb",
				Config:    tidbCfg,
			},
			TiKV: &v1alpha1.TiKVSpec{
				ComponentSpec: v1alpha1.ComponentSpec{
					Version:          &version,
					ImagePullPolicy:  nil,
					ImagePullSecrets: nil,
				},
				BaseImage: "tikv",
				Config:    tikvCfg,
			},
			TiFlash: &v1alpha1.TiFlashSpec{
				ComponentSpec: v1alpha1.ComponentSpec{
					Version:          &version,
					ImagePullPolicy:  nil,
					ImagePullSecrets: nil,
				},
				BaseImage: "tiflash",
				Config: &v1alpha1.TiFlashConfigWraper{
					Common: &v1alpha1.TiFlashCommonConfigWraper{
						GenericConfig: operatorconfig.New(map[string]interface{}{
							"security": map[string]interface{}{
								"cert_allowed_cn": "test",
							},
						}),
					},
					Proxy: &v1alpha1.TiFlashProxyConfigWraper{
						GenericConfig: operatorconfig.New(map[string]interface{}{
							"security": map[string]interface{}{
								"cert-allowed-cn": "test",
							},
						}),
					},
				},
			},
		},
	}
}
