package imports

import (
	"fmt"
	"testing"

	"github.com/google/go-cmp/cmp"
	. "github.com/onsi/gomega"
	corev1 "k8s.io/api/core/v1"
	"sigs.k8s.io/yaml"

	"github.com/tidbcloud/infra-api/pkg/consts"
)

func TestLightningService(t *testing.T) {
	var (
		fakeName = "fakeName"
		fakeNS   = "fakeNamespace"
		instance = "db"
	)
	cases := map[string]struct {
		expectSpec string
	}{
		fmt.Sprintf("Import_Service"): {`
  ports:
  - port: 8289
    protocol: TCP
    targetPort: 8289
  selector:
    app.kubernetes.io/name: fakeName`},
	}
	for name, tc := range cases {
		t.Run(name, func(t *testing.T) {
			g := NewGomegaWithT(t)
			svc := newLightningService(fakeName, fakeNS, instance)

			var expectSvc corev1.Service
			expectYaml := fmt.Sprintf(`metadata:
  creationTimestamp: null
  labels:
    app.kubernetes.io/component: tidb-lightning
    app.kubernetes.io/instance: db
    app.kubernetes.io/name: fakeName
  name: fakeName
  namespace: fakeNamespace
spec:%s`, tc.expectSpec)
			err := yaml.Unmarshal([]byte(expectYaml), &expectSvc)
			g.Expect(err).NotTo(HaveOccurred())
			diff := cmp.Diff(&expectSvc, svc)
			g.Expect(diff).To(BeEmpty())
		})
	}
}

func TestPersistentVolumeClaim(t *testing.T) {
	var (
		fakeName = "fakeName"
		fakeNS   = "fakeNamespace"
		fakeSC   = "fakeStorageClass"
		fakeRL   = "100"
		instance = "db"
	)
	cases := map[string]struct {
		expectSpec string
	}{
		fmt.Sprintf("Import_Service"): {`
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: "100"
  storageClassName: fakeStorageClass`},
	}
	for name, tc := range cases {
		t.Run(name, func(t *testing.T) {
			g := NewGomegaWithT(t)
			pvc := newPersistentVolumeClaim(fakeName, fakeNS, instance, fakeSC, fakeRL)

			var expectPvc corev1.PersistentVolumeClaim
			expectYaml := fmt.Sprintf(`metadata:
  creationTimestamp: null
  labels:
    app.kubernetes.io/component: tidb-lightning
    app.kubernetes.io/instance: db
    app.kubernetes.io/name: fakeName
  name: fakeName
  namespace: fakeNamespace
spec:%s`, tc.expectSpec)
			err := yaml.Unmarshal([]byte(expectYaml), &expectPvc)
			g.Expect(err).NotTo(HaveOccurred())
			diff := cmp.Diff(&expectPvc, pvc)
			g.Expect(diff).To(BeEmpty())
		})
	}
}

func TestLightningSecret(t *testing.T) {
	var (
		fakeName = "fakeName"
		fakeNS   = "fakeNamespace"
		fakeCfg  = "fakeConfig"
		fakeCred = []byte("fakeCredentials")
		instance = "db"
	)
	cases := map[string]struct {
		provider   string
		cred       []byte
		expectData string
	}{
		"aws-cred-nonzero": {consts.ProviderTypeAWS, fakeCred, `
  credentiascriptls: ZmFrZUNyZWRlbnRpYWxz
  tidb-lightning.toml: ZmFrZUNvbmZpZw==`},
		"aws-cred-zero": {consts.ProviderTypeAWS, nil, `
  tidb-lightning.toml: ZmFrZUNvbmZpZw==`},
		"aws-free-tier-cred-nonzero": {consts.ProviderTypeAWSFreeTier, fakeCred, `
  credentiascriptls: ZmFrZUNyZWRlbnRpYWxz
  tidb-lightning.toml: ZmFrZUNvbmZpZw==`},
		"aws-free-tier-cred-zero": {consts.ProviderTypeAWSFreeTier, nil, `
  tidb-lightning.toml: ZmFrZUNvbmZpZw==`},
		"aws-shared-tier-cred-nonzero": {consts.ProviderTypeAWSSharedTier, fakeCred, `
  credentiascriptls: ZmFrZUNyZWRlbnRpYWxz
  tidb-lightning.toml: ZmFrZUNvbmZpZw==`},
		"aws-shared-tier-cred-zero": {consts.ProviderTypeAWSSharedTier, nil, `
  tidb-lightning.toml: ZmFrZUNvbmZpZw==`},
		"gcp-cred-nonzero": {consts.ProviderTypeGCP, fakeCred, `
  privateKey: ZmFrZUNyZWRlbnRpYWxz
  tidb-lightning.toml: ZmFrZUNvbmZpZw==`},
		"gcp-cred-zero": {consts.ProviderTypeGCP, nil, `
  privateKey: null
  tidb-lightning.toml: ZmFrZUNvbmZpZw==`},
		"gcp-shared-tier-cred-nonzero": {consts.ProviderTypeGCP, fakeCred, `
  privateKey: ZmFrZUNyZWRlbnRpYWxz
  tidb-lightning.toml: ZmFrZUNvbmZpZw==`},
		"gcp-shared-tier-cred-zero": {consts.ProviderTypeGCP, nil, `
  privateKey: null
  tidb-lightning.toml: ZmFrZUNvbmZpZw==`},
	}
	for name, tc := range cases {
		t.Run(name, func(t *testing.T) {
			g := NewGomegaWithT(t)
			sec := newLightningSecret(tc.provider, fakeName, fakeNS, instance, fakeCfg, tc.cred)

			var expectSec corev1.Secret
			expectYaml := fmt.Sprintf(`
metadata:
  creationTimestamp: null
  labels:
    app.kubernetes.io/component: tidb-lightning
    app.kubernetes.io/instance: db
    app.kubernetes.io/name: fakeName
  name: fakeName
  namespace: fakeNamespace
data:%s`, tc.expectData)
			err := yaml.Unmarshal([]byte(expectYaml), &expectSec)
			g.Expect(err).NotTo(HaveOccurred())
			diff := cmp.Diff(&expectSec, sec)
			g.Expect(diff).To(BeEmpty())
		})
	}
}

func TestImportErrorMessageDigest(t *testing.T) {
	g := NewGomegaWithT(t)

	prefix := "awfeasdfwaer"
	ans := importErrorMessageDigest(prefix + "\nasdfqwae\nfwe")
	g.Expect(ans).To(Equal(prefix))

	prefix = "RequestCanceled: request context canceled"
	ans = importErrorMessageDigest(prefix + "\ncaused by: context canceled\ngithub.com/ping")
	g.Expect(ans).To(Equal(prefix))

	// no \n
	ans = importErrorMessageDigest(prefix)
	g.Expect(ans).To(Equal(prefix))

	// empty info,check for panic
	ans = importErrorMessageDigest("\n")
	g.Expect(ans).To(Equal(""))
}
