package cert

import (
	"errors"
	"fmt"
	"os"

	"github.com/docker/machine/libmachine/auth"
	"github.com/docker/machine/libmachine/log"
	"github.com/docker/machine/libmachine/mcnutils"
)

func BootstrapCertificates(authOptions *auth.Options) error {
	certDir := authOptions.CertDir
	caCertPath := authOptions.CaCertPath
	caPrivateKeyPath := authOptions.CaPrivateKeyPath
	clientCertPath := authOptions.ClientCertPath
	clientKeyPath := authOptions.ClientKeyPath

	// TODO: I'm not super happy about this use of "org", the user should
	// have to specify it explicitly instead of implicitly basing it on
	// $USER.
	caOrg := mcnutils.GetUsername()
	org := caOrg + ".<bootstrap>"

	bits := 2048

	if _, err := os.Stat(certDir); err != nil {
		if os.IsNotExist(err) {
			if err := os.MkdirAll(certDir, 0700); err != nil {
				return fmt.Errorf("Creating machine certificate dir failed: %s", err)
			}
		} else {
			return err
		}
	}

	if _, err := os.Stat(caCertPath); os.IsNotExist(err) {
		log.Infof("Creating CA: %s", caCertPath)

		// check if the key path exists; if so, error
		if _, err := os.Stat(caPrivateKeyPath); err == nil {
			return errors.New("certificate authority key already exists")
		}

		if err := GenerateCACertificate(caCertPath, caPrivateKeyPath, caOrg, bits); err != nil {
			return fmt.Errorf("Generating CA certificate failed: %s", err)
		}
	}

	if _, err := os.Stat(clientCertPath); os.IsNotExist(err) {
		log.Infof("Creating client certificate: %s", clientCertPath)

		if _, err := os.Stat(certDir); err != nil {
			if os.IsNotExist(err) {
				if err := os.Mkdir(certDir, 0700); err != nil {
					return fmt.Errorf("failure creating machine client cert dir: %s", err)
				}
			} else {
				return err
			}
		}

		// check if the key path exists; if so, error
		if _, err := os.Stat(clientKeyPath); err == nil {
			return errors.New("client key already exists")
		}

		// Used to generate the client certificate.
		certOptions := &Options{
			Hosts:       []string{""},
			CertFile:    clientCertPath,
			KeyFile:     clientKeyPath,
			CAFile:      caCertPath,
			CAKeyFile:   caPrivateKeyPath,
			Org:         org,
			Bits:        bits,
			SwarmMaster: false,
		}

		if err := GenerateCert(certOptions); err != nil {
			return fmt.Errorf("failure generating client certificate: %s", err)
		}
	}

	return nil
}
