package jump

import (
	"testing"

	"github.com/onsi/ginkgo/v2"
	"github.com/onsi/gomega"
	"github.com/tidbcloud/devops/pkg/infra/utils/test"
)

func TestCredential(t *testing.T) {
	gomega.RegisterFailHandler(ginkgo.Fail)
	ginkgo.RunSpecs(t, "Jump Entity Credential Suite", test.ReporterConfig())
}

type destinationCase struct {
	name string
	dest IDestination
	want CredentialID
}

var _ = ginkgo.Describe("[Credential]", func() {
	destinationCases := []destinationCase{
		{
			name: "unspecified destination",
			dest: &DestinationUnspecified{},
			want: "unspecified.unspecified",
		},
		{
			name: "control plane destination",
			dest: &DestinationControlPlane{Name: "infra-apiserver"},
			want: "controlplane.infra-apiserver",
		},
		{
			name: "dedicated cluster destination",
			dest: &DestinationDedicatedCluster{ClusterID: 123456},
			want: "dedicated.123456",
		},
		{
			name: "serverless cluster destination",
			dest: &DestinationServerlessCluster{Name: "serverless-prod"},
			want: "serverless.serverless-prod",
		},
		{
			name: "byoc cluster destination",
			dest: &DestinationByocCluster{BastionName: "bastion-use1"},
			want: "byoc.bastion-use1",
		},
		{
			name: "premium cluster destination",
			dest: &DestinationPremiumCluster{ClusterID: 654321},
			want: "premium.654321",
		},
		{
			name: "premium resource pool destination",
			dest: &DestinationPremiumResourcePool{ResourcePoolID: 987654},
			want: "premium_resource_pool.987654",
		},
	}

	ginkgo.DescribeTable("formats credential IDs for every destination implementation",
		table(func(tc destinationCase) {
			gomega.Expect(FormatCredentialID(tc.dest)).To(gomega.Equal(tc.want))
		}, destinationCases)...,
	)

	ginkgo.DescribeTable("formats gateway credential IDs for every destination implementation",
		table(func(tc destinationCase) {
			gomega.Expect(FormatGatewayCredentialID(tc.dest)).To(gomega.Equal(CredentialID("gateway_" + string(tc.want))))
		}, destinationCases)...,
	)

	ginkgo.DescribeTable("parses credential IDs for every destination implementation",
		table(func(tc destinationCase) {
			typ, id := ParseCredentialID(tc.want)

			gomega.Expect(typ).To(gomega.Equal(tc.dest.Type()))
			gomega.Expect(id).To(gomega.Equal(tc.dest.ID()))
		}, destinationCases)...,
	)

	ginkgo.DescribeTable("parses gateway credential IDs for every destination implementation",
		table(func(tc destinationCase) {
			typ, id := ParseCredentialID(FormatGatewayCredentialID(tc.dest))

			gomega.Expect(typ).To(gomega.Equal(tc.dest.Type()))
			gomega.Expect(id).To(gomega.Equal(tc.dest.ID()))
		}, destinationCases)...,
	)

	ginkgo.Describe("[IsGatewayCredentialID]", func() {
		ginkgo.It("returns true only for gateway credential IDs", func() {
			gomega.Expect(IsGatewayCredentialID("gateway_controlplane.infra-apiserver")).To(gomega.BeTrue())
			gomega.Expect(IsGatewayCredentialID("controlplane.infra-apiserver")).To(gomega.BeFalse())
			gomega.Expect(IsGatewayCredentialID("invalid")).To(gomega.BeFalse())
		})
	})
})

func table(body func(destinationCase), cases []destinationCase) []any {
	entries := make([]any, 0, len(cases)+1)
	entries = append(entries, body)
	for _, tc := range cases {
		entries = append(entries, ginkgo.Entry(tc.name, tc))
	}

	return entries
}
