package util

import (
	"context"
	"crypto/tls"
	"crypto/x509"
	"fmt"

	pd "github.com/tikv/pd/client"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"
	apierrors "k8s.io/apimachinery/pkg/api/errors"

	corev1 "k8s.io/api/core/v1"
	types "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
)

func GetTLSConfig(kubeCli kubernetes.Interface, namespace string, tcName string, secretName string) (*tls.Config, error) {
	secret, err := kubeCli.CoreV1().Secrets(namespace).Get(context.TODO(), secretName, types.GetOptions{})
	if err != nil {
		if apierrors.IsNotFound(err) {
			// dev tier no TLS
			return nil, nil
		} else {
			return nil, fmt.Errorf("unable to load certificates from secret %s/%s: %v", namespace, secretName, err)
		}
	}

	return LoadTlsConfigFromSecret(secret)
}

func GetGRPCConfig(tlsCfg *tls.Config) grpc.DialOption {
	return grpc.WithTransportCredentials(credentials.NewTLS(tlsCfg))
}

func GetPDSecurityOption(ctx context.Context, kubeCli kubernetes.Interface, namespace string, tcName string, secretName string) (*pd.SecurityOption, error) {
	secret, err := kubeCli.CoreV1().Secrets(namespace).Get(ctx, secretName, types.GetOptions{})
	if err != nil {
		return nil, fmt.Errorf("unable to load certificates from secret %s/%s: %v", namespace, secretName, err)
	}

	clientCert, certExists := secret.Data[corev1.TLSCertKey]
	clientKey, keyExists := secret.Data[corev1.TLSPrivateKeyKey]
	if !certExists || !keyExists {
		return nil, fmt.Errorf("cert or key does not exist in secret %s/%s", secret.Namespace, secret.Name)
	}
	return &pd.SecurityOption{
		SSLCABytes:   secret.Data[corev1.ServiceAccountRootCAKey],
		SSLCertBytes: clientCert,
		SSLKEYBytes:  clientKey,
	}, nil
}

func LoadTlsConfigFromSecret(secret *corev1.Secret) (*tls.Config, error) {
	rootCAs := x509.NewCertPool()
	var tlsCert tls.Certificate

	rootCAs.AppendCertsFromPEM(secret.Data[corev1.ServiceAccountRootCAKey])

	clientCert, certExists := secret.Data[corev1.TLSCertKey]
	clientKey, keyExists := secret.Data[corev1.TLSPrivateKeyKey]
	if !certExists || !keyExists {
		return nil, fmt.Errorf("cert or key does not exist in secret %s/%s", secret.Namespace, secret.Name)
	}
	tlsCert, err := tls.X509KeyPair(clientCert, clientKey)
	if err != nil {
		return nil, fmt.Errorf("unable to load certificates from secret %s/%s: %v", secret.Namespace, secret.Name, err)
	}

	return &tls.Config{
		InsecureSkipVerify: true,
		RootCAs:            rootCAs,
		Certificates:       []tls.Certificate{tlsCert},
	}, nil
}
