package k8scliv2

import (
	"context"
	"fmt"

	gkev1beta2 "github.com/upbound/provider-gcp/apis/container/v1beta2"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"
	clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
	resourceclient "k8s.io/metrics/pkg/client/clientset/versioned/typed/metrics/v1beta1"
	"sigs.k8s.io/controller-runtime/pkg/client"
)

const (
	gkeExecConfigAPIVersion = "client.authentication.k8s.io/v1beta1"
)

type gkeTenantClientManager struct {
	cli    client.Client
	option client.Options
}

func NewGKETenantClientManager(cli client.Client, opt client.Options) ClientManager {
	return &gkeTenantClientManager{
		cli:    cli,
		option: opt,
	}
}

func (t *gkeTenantClientManager) GetClient(ctx context.Context, cluster client.ObjectKey) (client.Client, error) {
	restCfg, err := t.GetConfig(ctx, cluster)
	if err != nil {
		return nil, err
	}
	cli, err := client.New(restCfg, t.option)
	if err != nil {
		return nil, err
	}
	return cli, nil
}

func (t *gkeTenantClientManager) GetMetricsClient(ctx context.Context, cluster client.ObjectKey) (resourceclient.MetricsV1beta1Interface, error) {
	restCfg, err := t.GetConfig(ctx, cluster)
	if err != nil {
		return nil, err
	}
	return resourceclient.NewForConfig(restCfg)
}

func (t *gkeTenantClientManager) GetConfig(ctx context.Context, gkeKey client.ObjectKey) (*rest.Config, error) {
	gke := &gkev1beta2.Cluster{}
	err := t.cli.Get(ctx, gkeKey, gke)
	if err != nil {
		return nil, err
	}
	cfg := clientcmdapi.NewConfig()

	cfgctx := clientcmdapi.NewContext()
	cfgctx.Cluster = gke.Name
	cfgctx.AuthInfo = gke.Name

	cluster := clientcmdapi.NewCluster()
	// TODO: get ca data from gcp
	cluster.InsecureSkipTLSVerify = true
	// cluster.CertificateAuthorityData = []byte(gke.Status.AtProvider.CertificateAuthorityData)
	cluster.Server = fmt.Sprintf("https://%s", *gke.Status.AtProvider.Endpoint)

	auth := clientcmdapi.NewAuthInfo()
	auth.Exec = &clientcmdapi.ExecConfig{
		APIVersion:      gkeExecConfigAPIVersion,
		InteractiveMode: clientcmdapi.NeverExecInteractiveMode,
		Command:         "gke-gcloud-auth-plugin",
		Args:            []string{"--use_application_default_credentials"},
	}

	cfg.Contexts[gke.Name] = cfgctx
	cfg.Clusters[gke.Name] = cluster
	cfg.AuthInfos[gke.Name] = auth
	cfg.CurrentContext = gke.Name

	return clientcmd.NewDefaultClientConfig(*cfg, nil).ClientConfig()
}

type gkeLocalClientManager struct {
	restCfg *rest.Config
	option  client.Options
}

func NewGKELocalClientManager(restCfg *rest.Config, opt client.Options) ClientManager {
	return &gkeLocalClientManager{
		restCfg: restCfg,
		option:  opt,
	}
}

func (mgr *gkeLocalClientManager) GetConfig(ctx context.Context, _ client.ObjectKey) (*rest.Config, error) {
	return mgr.restCfg, nil
}

func (mgr *gkeLocalClientManager) GetClient(ctx context.Context, _ client.ObjectKey) (client.Client, error) {
	return client.New(mgr.restCfg, mgr.option)
}

func (mgr *gkeLocalClientManager) GetMetricsClient(ctx context.Context, _ client.ObjectKey) (resourceclient.MetricsV1beta1Interface, error) {
	return resourceclient.NewForConfig(mgr.restCfg)
}
