package _tests_test

import (
	"fmt"
	"math/rand"
	"os"
	"os/exec"
	"os/user"
	"path"

	. "github.com/onsi/ginkgo"

	. "github.com/onsi/gomega"

	"testing"
	"time"
)

const (
	deisWorkflowServiceHost = "DEIS_WORKFLOW_SERVICE_HOST"
	deisWorkflowServicePort = "DEIS_WORKFLOW_SERVICE_PORT"
)

func init() {
	rand.Seed(GinkgoConfig.RandomSeed)
}

func getRandAppName() string {
	return fmt.Sprintf("apps-test-%d", rand.Int())
}

func TestTests(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "Tests Suite")
}

var (
	testAdminUser     = fmt.Sprintf("test-admin-%d", GinkgoConfig.RandomSeed)
	testAdminPassword = "asdf1234"
	testAdminEmail    = fmt.Sprintf("test-admin-%d@deis.io", GinkgoConfig.RandomSeed)
	testUser          = fmt.Sprintf("test-%d", GinkgoConfig.RandomSeed)
	testPassword      = "asdf1234"
	testEmail         = fmt.Sprintf("test-%d@deis.io", GinkgoConfig.RandomSeed)
	url               = getController()
)

var _ = BeforeSuite(func() {
	// use the "deis" executable in the search $PATH
	_, err := exec.LookPath("deis")
	Expect(err).NotTo(HaveOccurred())

	// register the test-admin user
	register(url, testAdminUser, testAdminPassword, testAdminEmail)
	// verify this user is an admin by running a privileged command
	Expect(cmd("deis users:list")).To(BeASuccessfulCmd())

	// register the test user and add a key
	register(url, testUser, testPassword, testEmail)
	createKey("deis-test")
	Expect(cmd("deis keys:add ~/.ssh/deis-test.pub")).To(BeASuccessfulCmdWithOutput(
		ContainSubstring("Uploading deis-test.pub to deis... done"),
	))
})

var _ = AfterSuite(func() {
	// cancel the test user
	cancel(url, testUser, testPassword)

	// cancel the test-admin user
	cancel(url, testAdminUser, testAdminPassword)
})

func register(url, username, password, email string) {
	Expect(cmd("deis register %s --username=%s --password=%s --email=%s", url, username, password, email)).To(BeASuccessfulCmdWithOutput(
		ContainSubstring("Registered %s", username),
		ContainSubstring("Logged in as %s", username),
	))
}

func cancel(url, username, password string) {
	// log in to the account
	login(url, username, password)

	// cancel the account
	Expect(cmd("deis auth:cancel --username=%s --password=%s --yes", username, password)).To(BeASuccessfulCmdWithOutput(
		ContainSubstring("Account cancelled"),
	))
}

func login(url, user, password string) {
	Expect(cmd("deis login %s --username=%s --password=%s", url, user, password)).To(BeASuccessfulCmdWithOutput(
		ContainSubstring("Logged in as %s", user),
	))
}

func logout() {
	Expect(cmd("deis auth:logout")).To(BeASuccessfulCmdWithOutput(
		Equal("Logged out\n"),
	))
}

// execute executes the command generated by fmt.Sprintf(cmdLine, args...) and returns its output as a cmdOut structure.
// this structure can then be matched upon using the SucceedWithOutput matcher below
func execute(cmdLine string, args ...interface{}) (string, error) {
	c := cmd(cmdLine, args...)
	return c.stdout, c.err
}

func createKey(name string) {
	var home string
	if user, err := user.Current(); err != nil {
		home = "~"
	} else {
		home = user.HomeDir
	}
	path := path.Join(home, ".ssh", name)
	// create the key under ~/.ssh/<name> if it doesn't already exist
	if _, err := os.Stat(path); os.IsNotExist(err) {
		Expect(cmd("ssh-keygen -q -t rsa -b 4096 -C %s -f %s -N ''", name, path)).To(BeASuccessfulCmd())
	}
	// add the key to ssh-agent
	Expect(cmd("eval $(ssh-agent) && ssh-add %s", path)).To(BeASuccessfulCmd())
}

func getController() string {
	host := os.Getenv(deisWorkflowServiceHost)
	if host == "" {
		panicStr := fmt.Sprintf(`Set %s to the workflow controller hostname for tests, such as:

$ %s=deis.10.245.1.3.xip.io make test-integration`, deisWorkflowServiceHost, deisWorkflowServiceHost)
		panic(panicStr)
	}
	port := os.Getenv(deisWorkflowServicePort)
	switch port {
	case "443":
		return "https://" + host
	case "80", "":
		return "http://" + host
	default:
		return fmt.Sprintf("http://%s:%s", host, port)
	}
}
