package clients

import (
	"os"

	"github.com/golang/glog"
	configclientset "github.com/openshift/client-go/config/clientset/versioned"
	operatorclientset "github.com/openshift/client-go/operator/clientset/versioned"
	mcfgclientset "github.com/openshift/machine-config-operator/pkg/generated/clientset/versioned"
	apiext "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"
)

// Builder can create a variety of kubernetes client interface
// with its embedded rest.Config.
type Builder struct {
	config *rest.Config
}

// MachineConfigClientOrDie returns the kubernetes client interface for machine config.
func (cb *Builder) MachineConfigClientOrDie(name string) mcfgclientset.Interface {
	return mcfgclientset.NewForConfigOrDie(rest.AddUserAgent(cb.config, name))
}

// MachineConfigClient is used in onceFrom mode where we can or cannot have a cluster ready
// based on the configuration provided
func (cb *Builder) MachineConfigClient(name string) (mcfgclientset.Interface, error) {
	return mcfgclientset.NewForConfig(rest.AddUserAgent(cb.config, name))
}

// KubeClientOrDie returns the kubernetes client interface for general kubernetes objects.
func (cb *Builder) KubeClientOrDie(name string) kubernetes.Interface {
	return kubernetes.NewForConfigOrDie(rest.AddUserAgent(cb.config, name))
}

// KubeClient is used in onceFrom mode where we can or cannot have a cluster ready
// based on the configuration provided
func (cb *Builder) KubeClient(name string) (kubernetes.Interface, error) {
	return kubernetes.NewForConfig(rest.AddUserAgent(cb.config, name))
}

// ConfigClientOrDie returns the config client interface for openshift
func (cb *Builder) ConfigClientOrDie(name string) configclientset.Interface {
	return configclientset.NewForConfigOrDie(rest.AddUserAgent(cb.config, name))
}

// OperatorClientOrDie returns the kubernetes client interface for operator-specific configuration.
func (cb *Builder) OperatorClientOrDie(name string) operatorclientset.Interface {
	return operatorclientset.NewForConfigOrDie(rest.AddUserAgent(cb.config, name))
}

// APIExtClientOrDie returns the kubernetes client interface for extended kubernetes objects.
func (cb *Builder) APIExtClientOrDie(name string) apiext.Interface {
	return apiext.NewForConfigOrDie(rest.AddUserAgent(cb.config, name))
}

// NewBuilder returns a *ClientBuilder with the given kubeconfig.
func NewBuilder(kubeconfig string) (*Builder, error) {
	var config *rest.Config
	var err error

	if kubeconfig == "" {
		kubeconfig = os.Getenv("KUBECONFIG")
	}

	if kubeconfig != "" {
		glog.V(4).Infof("Loading kube client config from path %q", kubeconfig)
		config, err = clientcmd.BuildConfigFromFlags("", kubeconfig)
	} else {
		glog.V(4).Infof("Using in-cluster kube client config")
		config, err = rest.InClusterConfig()
	}
	if err != nil {
		return nil, err
	}

	return &Builder{
		config: config,
	}, nil
}
