package k8s

import (
	"context"
	"fmt"
	"testing"

	cpv1beta1 "github.com/crossplane/provider-aws/apis/eks/v1beta1"
	. "github.com/onsi/gomega"
	"k8s.io/apimachinery/pkg/api/meta"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/client-go/kubernetes/scheme"
	"sigs.k8s.io/aws-iam-authenticator/pkg/token"
	"sigs.k8s.io/controller-runtime/pkg/client"
	_ "sigs.k8s.io/controller-runtime/pkg/client"
	"sigs.k8s.io/controller-runtime/pkg/client/fake"
	_ "sigs.k8s.io/controller-runtime/pkg/client/fake"
)

const (
	defaultClusterName = "eks1"
	defaultNamespace   = "default"
	defaultClusterARN  = "arn:aws:eks:us-west-2:123456789012:cluster/eks1"
	defaultClusterEP   = "localhost"
)

var (
	defaultEKSCluster cpv1beta1.Cluster
)

func init() {
	defaultEKSCluster.Name = defaultClusterName
	defaultEKSCluster.Namespace = defaultNamespace
	defaultEKSCluster.Status.AtProvider.Arn = defaultClusterARN
	defaultEKSCluster.Status.AtProvider.Endpoint = defaultClusterEP
}

func TestGetClient(t *testing.T) {
	cases := map[string]struct {
		opt       EKSClientOpt
		clientOpt client.Options
		objs      []client.Object
		tokenGen  *fakeGenerator
		expectErr bool
	}{
		"token-success": {
			opt: EKSClientOpt{
				EKSTarget: defaultTarget(),
				EKSObject: client.ObjectKey{
					Name:      defaultClusterName,
					Namespace: defaultNamespace,
				},
			},
			clientOpt: client.Options{
				Mapper: &meta.DefaultRESTMapper{},
			},
			objs: []client.Object{&defaultEKSCluster},
			tokenGen: &fakeGenerator{
				fakeToken: token.Token{Token: "fake-token"},
				fakeJson:  "fake-json",
			},
		},
		"token-error": {
			opt: EKSClientOpt{
				EKSTarget: defaultTarget(),
				EKSObject: client.ObjectKey{
					Name:      defaultClusterName,
					Namespace: defaultNamespace,
				},
			},
			clientOpt: client.Options{
				Mapper: &meta.DefaultRESTMapper{},
			},
			objs: []client.Object{&defaultEKSCluster},
			tokenGen: &fakeGenerator{
				fakeErr: fmt.Errorf("some error"),
			},
			expectErr: true,
		},
		"cluster-cr-missing": {
			opt: EKSClientOpt{
				EKSTarget: defaultTarget(),
				EKSObject: client.ObjectKey{
					Name:      defaultClusterName,
					Namespace: defaultNamespace,
				},
			},
			clientOpt: client.Options{
				Mapper: &meta.DefaultRESTMapper{},
			},
			tokenGen: &fakeGenerator{
				fakeToken: token.Token{Token: "fake-token"},
				fakeJson:  "fake-json",
			},
			expectErr: true,
		},
	}
	for name, tc := range cases {
		t.Run(name, func(t *testing.T) {
			g := NewGomegaWithT(t)
			s := runtime.NewScheme()
			g.Expect(scheme.AddToScheme(s)).To(Succeed())
			g.Expect(cpv1beta1.SchemeBuilder.AddToScheme(s)).To(Succeed())
			cli := fake.NewClientBuilder().WithScheme(s).WithObjects(tc.objs...).Build()
			e := NewEKSClientManager(cli, &eksTokenMngr{Client: cli, tokGen: tc.tokenGen}, tc.clientOpt)
			_, err := e.GetClient(context.TODO(), tc.opt)
			if !tc.expectErr {
				g.Expect(err).To(Succeed())
			} else {
				g.Expect(err).NotTo(Succeed())
			}
		})
	}
	return
}
