// +build mage

package main

import (
	"context"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"

	"github.com/jtolds/qod"
	"github.com/magefile/mage/mg"
)

var wd string
var arches []string

func init() {
	lwd, err := os.Getwd()
	qod.ANE(err)

	wd = lwd

	arches = []string{"amd64", "ppc64", "386", "arm", "arm64"}
}

const pkgBase = "git.xeserv.us/xena/route/"

func buildBins(goos, goarch string) {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	d := filepath.Join(wd, "./bin")

	os.MkdirAll(filepath.Join(d, goos, goarch), 0777)

	for _, pkg := range []string{"route-httpagent", "route-cli", "routed", "terraform-provider-route"} {
		env := []string{"GOOS=" + goos, "GOARCH=" + goarch}
		goBuild(ctx, env, filepath.Join(d, goos, goarch), "cmd/"+pkg)
		goInstall(ctx, env, "cmd/"+pkg)

		qod.Printlnf("built binary for %s for %s/%s", pkg, goos, goarch)
	}
}

// Dep reruns `dep`.
func Dep() {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	shouldWork(ctx, nil, wd, "dep", "ensure")
	shouldWork(ctx, nil, wd, "dep", "prune")
}

// Docker builds docker images
func Docker() {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	ver, err := gitTag()
	qod.ANE(err)

	shouldWork(ctx, nil, wd, "docker", "build", "-t", "xena/route-core", "-f", "Dockerfile.core", ".")
	shouldWork(ctx, nil, wd, "docker", "build", "-t", "xena/routed:"+ver, "-f", "Dockerfile.routed", ".")
	shouldWork(ctx, nil, wd, "docker", "build", "-t", "xena/route-httpagent:"+ver, "-f", "Dockerfile.agent", ".")
}

// Linux builds binaries for linux
func Linux() {
	for _, arch := range arches {
		buildBins("linux", arch)
	}
	Plugin()
}

// Windows builds binaries for windows
func Windows() {
	buildBins("windows", "amd64")
}

// Darwin builds binaries for darwin
func Darwin() {
	buildBins("darwin", "amd64")
}

// Build builds the binaries for route and routed.
func Build() {
	buildBins(runtime.GOOS, runtime.GOARCH)
}

// Plugin builds all of the plugins for programs wanting to augment themselves with route.
func Plugin() {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	goBuildPlugin(ctx, filepath.Join(wd, "./bin/linux"), "plugins/autohttpagent", "autohttpagent.so")
}

// Package builds all binaries for all platforms and assembles a package of
// documentation, useful tools and all route components.
func Package() {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	os.RemoveAll("./bin/darwin")
	os.RemoveAll("./bin/linux")
	os.RemoveAll("./bin/windows")

	mg.Deps(Linux, Windows, Darwin)

	ver, err := gitTag()
	qod.ANE(err)

	for _, arch := range arches {
		for _, osname := range []string{"linux", "windows", "darwin"} {
			if arch != "amd64" && osname != "linux" {
				continue
			}

			dir, err := ioutil.TempDir("", "route-package-"+osname+"-"+arch)
			qod.ANE(err)
			qod.Printlnf("%s", dir)

			for _, file := range []string{"route-cli", "route-httpagent", "routed"} {
				if osname == "windows" {
					file = file + ".exe"
				}
				shouldWork(ctx, nil, filepath.Join(wd, "bin", osname, arch), "cp", "-rf", file, dir)
			}

			shouldWork(ctx, nil, wd, "cp", "-rf", "doc", dir)
			shouldWork(ctx, nil, wd, "cp", "-rf", "README.md", dir)
			shouldWork(ctx, nil, wd, "cp", "-rf", "LICENSE", dir)
			shouldWork(ctx, nil, wd, "cp", "-rf", "Gopkg.lock", dir)

			shouldWork(ctx, nil, dir, "tar", "czf", filepath.Join(wd, "bin", fmt.Sprintf("route-%s-%s-%s.tar.gz", ver, osname, arch)), ".")
		}
	}
}

// Test runs all of the functional and unit tests for the project.
func Test() {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	shouldWork(ctx, nil, wd, "go", "test", "-v", "./...")
}

// Tools installs all of the needed tools for the project.
func Tools(ctx context.Context) {
	tools := []string{
		"github.com/golang/dep/cmd/dep",
		"github.com/golang/protobuf/protoc-gen-go",
		"github.com/twitchtv/twirp/protoc-gen-twirp",
		"github.com/jteeuwen/go-bindata/go-bindata",
	}

	for _, t := range tools {
		shouldWork(ctx, nil, wd, "go", "get", "-u", t)
	}
}

// Generate runs code generators and the like.
func Generate(ctx context.Context) {
	protoDir := filepath.Join(wd, "proto")
	databaseDir := filepath.Join(wd, "internal", "database")

	os.Mkdir(filepath.Join(databaseDir, "dmigrations"), 0777)

	Tools(ctx)

	shouldWork(ctx, nil, protoDir, "sh", "./regen.sh")
	shouldWork(ctx, nil, databaseDir, "go-bindata", "-pkg", "dmigrations", "-o", "./dmigrations/bindata.go", "./migrations")
}

// Vars shows the various variables that this magefile uses.
func Vars() {
	ver, err := gitTag()
	qod.ANE(err)

	qod.Printlnf("arches:\t%v", arches)
	qod.Printlnf("goarch:\t%s", runtime.GOARCH)
	qod.Printlnf("goos:\t%s", runtime.GOOS)
	qod.Printlnf("wd:\t%s", wd)
	qod.Printlnf("ver:\t%s", ver)
}