package main

import (
	"flag"
	"log"
	"os"
	"os/exec"
	"path"
	"strings"
	"time"
)

func init() {
}

func main() {
	setid := flag.Bool("setid", false, "Set the git user name and email to benchmark")
	flag.Parse()

	log.Printf("Starting benchmarking...")

	if *setid {
		setId()
	}
	head := getHeadHash()
	log.Printf("HEAD at %s", head)

	err := os.MkdirAll("results", 0755)
	if err != nil {
		log.Fatalf("Error creating results directory with %v", err)
	}

	now := time.Now().Format(time.DateOnly)
	resultFile := path.Join(".", "results", now+"_"+head+".txt")
	log.Printf("Writing results to %s", resultFile)
	outFile, err := os.Create(resultFile)
	if err != nil {
		log.Fatalf("Error creating result file %s with %v", resultFile, err)
	}

	cmd := exec.Command("go", "test", "-bench", ".", "./...")
	cmd.Dir = "../"
	cmd.Stdout = outFile

	log.Printf("Running benchmark...")
	err = cmd.Run()
	if err != nil {
		log.Fatal(err)
	}

	log.Printf("Benchmarking done; writing results to git...")
	log.Printf("Removing local benchmark branch")
	removeLocalBenchmarkBranch()
	time.Sleep(200 * time.Millisecond)
	log.Printf("Fetching benchmark branch")
	fetchBenchmark()
	time.Sleep(200 * time.Millisecond)
	log.Printf("Tracking benchmark branch")
	trackBenchmark()
	time.Sleep(200 * time.Millisecond)
	log.Printf("Checking out benchmark branch")
	checkoutBenchmark()
	time.Sleep(200 * time.Millisecond)
	log.Printf("Adding benchmark results")
	addResults()
	time.Sleep(200 * time.Millisecond)
	log.Printf("Committing benchmark results")
	commitBenchmark()
	time.Sleep(200 * time.Millisecond)
	log.Printf("Pushing benchmark results")
	pushBenchmark()
	log.Printf("Done")
}

func removeLocalBenchmarkBranch() {
	gitBranch := exec.Command("git", "branch", "-D", "benchmark")
	gitBranch.Dir = "../"
	out, err := gitBranch.CombinedOutput()
	if err != nil {
		log.Printf("Could not remove local benchmark branch with code %v and error %v", err, string(out))
	}
}

func getHeadHash() string {
	cmd := exec.Command("git", "rev-parse", "HEAD")
	cmd.Dir = "../"
	out, err := cmd.CombinedOutput()
	if err != nil {
		log.Fatalf("Could not get HEAD with code %v and error %v", err, string(out))
	}
	return strings.TrimSpace(string(out))
}

func fetchBenchmark() {
	gitFetch := exec.Command("git", "fetch", "origin", "benchmark")
	gitFetch.Dir = "../"
	out, err := gitFetch.CombinedOutput()
	if err != nil {
		log.Fatalf("Could not fetch benchmark branch with code %v and error %v", err, string(out))
	}
}

func trackBenchmark() {
	gitTrack := exec.Command("git", "branch", "--track", "benchmark", "origin/benchmark")
	gitTrack.Dir = "../"
	out, err := gitTrack.CombinedOutput()
	if err != nil {
		log.Fatalf("Could not track benchmark branch with code %v and error %v", err, string(out))
	}
}

func checkoutBenchmark() {
	gitCheckout := exec.Command("git", "checkout", "benchmark")
	gitCheckout.Dir = "../"
	out, err := gitCheckout.CombinedOutput()
	if err != nil {
		log.Fatalf("Could not checkout benchmark branch with code %v and error %v", err, string(out))
	}
}

func setId() {
	gitConfig := exec.Command("git", "config", "user.name", "benchmark")
	gitConfig.Dir = "../"
	out, err := gitConfig.CombinedOutput()
	if err != nil {
		log.Fatalf("Could not set user name with code %v and error %v", err, string(out))
	}

	gitConfig = exec.Command("git", "config", "user.email", "benchmark@smpptester")
	gitConfig.Dir = "../"
	out, err = gitConfig.CombinedOutput()
	if err != nil {
		log.Fatalf("Could not set user email with code %v and error %v", err, string(out))
	}
}

func addResults() {
	gitAdd := exec.Command("git", "add", "benchmark/results")
	gitAdd.Dir = "../"
	out, err := gitAdd.CombinedOutput()
	if err != nil {
		log.Fatalf("Could not add results with code %v and error %v", err, string(out))
	}
}

func commitBenchmark() {
	gitCommit := exec.Command("git", "commit", "-am", "Benchmark results")
	gitCommit.Dir = "../"
	out, err := gitCommit.CombinedOutput()
	if err != nil {
		log.Fatalf("Could not commit benchmark results with code %v and error %v", err, string(out))
	}
}

func pushBenchmark() {
	gitPush := exec.Command("git", "push", "origin", "benchmark")
	gitPush.Dir = "../"
	out, err := gitPush.CombinedOutput()
	if err != nil {
		log.Fatalf("Could not push benchmark results with code %v and error %v", err, string(out))
	}
}
