package apiserver

import (
	"crypto/tls"
	"fmt"
	"io/ioutil"
	"os"
	"path"

	"github.com/coreos/etcd/pkg/transport"
	"github.com/pingcap/tep/pkg/controller"
	"github.com/pingcap/tep/pkg/etcdclient"
	"github.com/pingcap/tep/pkg/operator"
	"go.etcd.io/etcd/clientv3"
	corev1 "k8s.io/api/core/v1"
)

const (
	CliCertFile = "etcd-client.crt"
	CliKeyFile  = "etcd-client.key"
	CliCAFile   = "etcd-client-ca.crt"
	CertsDir    = "/etc/etcd/certs"
)

func createCertFile(secret *corev1.Secret, key string) error {
	cert, exist := secret.Data[key]
	if !exist {
		return fmt.Errorf("key[%s] not found in etcd secret[%s]", key, operator.EtcdSecretName)
	}

	err := ioutil.WriteFile(path.Join(CertsDir, key), cert, 0600)
	return err
}

func generateEtcdCert(ctrl *controller.Controller, namespace string) error {
	err := os.MkdirAll(CertsDir, 0700)
	if err != nil {
		return fmt.Errorf("failed to create directory[%s], err: %v", CertsDir, err)
	}

	secret, err := ctrl.GetSecret(operator.EtcdSecretName, namespace)
	if err != nil {
		return err
	}

	if err := createCertFile(secret, CliCertFile); err != nil {
		return err
	}
	if err := createCertFile(secret, CliKeyFile); err != nil {
		return err
	}
	err = createCertFile(secret, CliCAFile)
	return err
}

func newTLSConfig() (*tls.Config, error) {
	certFile := path.Join(CertsDir, CliCertFile)
	keyFile := path.Join(CertsDir, CliKeyFile)
	caFile := path.Join(CertsDir, CliCAFile)

	tlsInfo := transport.TLSInfo{
		CertFile:      certFile,
		KeyFile:       keyFile,
		TrustedCAFile: caFile,
	}
	tlsConfig, err := tlsInfo.ClientConfig()
	if err != nil {
		return nil, err
	}
	return tlsConfig, nil
}

func newEtcdClient(ctrl *controller.Controller, namespace string, endpoints []string) (*clientv3.Client, error) {
	err := generateEtcdCert(ctrl, namespace)
	if err != nil {
		return nil, fmt.Errorf("failed to generate etcd certs: %v", err)
	}

	tc, err := newTLSConfig()
	if err != nil {
		return nil, fmt.Errorf("failed to create tls config: %v", err)
	}

	etcdCli, err := etcdclient.New(endpoints, tc)
	return etcdCli, err
}
