// Licensed Materials - Property of IBM
// (c) Copyright IBM Corporation 2018, 2019. All Rights Reserved.
// Note to U.S. Government Users Restricted Rights:
// Use, duplication or disclosure restricted by GSA ADP Schedule
// Contract with IBM Corp.
// Copyright (c) 2020 Red Hat, Inc.

package sync

import (
	"fmt"
	"net/http"
	"os"
	"path/filepath"

	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/clientcmd"
	clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
	"k8s.io/client-go/util/certificate"
)

const (
	pairNamePrefix = "kubelet-client"
	currentPair    = "current"
	pemExtension   = ".pem"
)

func newNotFound(name, message string) *errors.StatusError {
	return &errors.StatusError{ErrStatus: metav1.Status{
		Status: metav1.StatusFailure,
		Code:   http.StatusNotFound,
		Reason: metav1.StatusReasonNotFound,
		Details: &metav1.StatusDetails{
			Name: name,
		},
		Message: message,
	}}
}

//LoadClientCert read key/cert from secret and write client cert and kubeconfig to the certain path
func LoadClientCert(hcmAPIHost, hcmConfigPath, certDir, secretName, secretNamespace string, localkubeclient kubernetes.Interface) error {
	if _, err := os.Stat(certDir); os.IsNotExist(err) {
		direrr := os.MkdirAll(certDir, 0750)
		if direrr != nil {
			return direrr
		}
	}

	store, err := certificate.NewFileStore(pairNamePrefix, certDir, certDir, "", "")
	if err != nil {
		return fmt.Errorf("unable to build bootstrap cert store")
	}

	secret, err := localkubeclient.Core().Secrets(secretNamespace).Get(secretName, metav1.GetOptions{})
	if err != nil {
		return err
	}

	key, ok := secret.Data["tls.key"]
	if !ok {
		return newNotFound("tls.key", "key is not found")
	}

	cert, ok := secret.Data["tls.crt"]
	if !ok {
		return newNotFound("tls.crt", "cert is not found")
	}

	if _, err := store.Update(cert, key); err != nil {
		return err
	}

	// with kube 1.11 you can do pemPath := store.CurrentPath() but since we
	// are not upgrading yet we need to do the following to get pemPath
	fn := pairNamePrefix + "-" + currentPair + pemExtension
	pemPath := filepath.Join(certDir, fn)
	hcmconfigData := clientcmdapi.Config{
		// Define a cluster stanza based on the bootstrap kubeconfig.
		Clusters: map[string]*clientcmdapi.Cluster{"default-cluster": {
			Server:                hcmAPIHost,
			InsecureSkipTLSVerify: true,
		}},
		// Define auth based on the obtained client cert.
		AuthInfos: map[string]*clientcmdapi.AuthInfo{"default-auth": {
			ClientCertificate: pemPath,
			ClientKey:         pemPath,
		}},
		// Define a context that connects the auth info and cluster, and set it as the default
		Contexts: map[string]*clientcmdapi.Context{"default-context": {
			Cluster:   "default-cluster",
			AuthInfo:  "default-auth",
			Namespace: "default",
		}},
		CurrentContext: "default-context",
	}

	return clientcmd.WriteToFile(hcmconfigData, hcmConfigPath)
}
