// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// The following enables go generate to generate the doc.go file.
//go:generate go run $JIRI_ROOT/release/go/src/v.io/x/lib/cmdline/testdata/gendoc.go .

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"regexp"
	"time"

	"v.io/jiri/tool"
	"v.io/x/lib/cmdline"
)

// TODO(jsimsa): Add tests by mocking out jenkins.
//
// TODO(jsimsa): Create a tools/lib/gcutil package that encapsulates
// the interaction with GCE and use it here and in the vcloud tool.
func main() {
	cmdline.Main(cmdVJenkins)
}

var cmdVJenkins = &cmdline.Command{
	Name:  "vjenkins",
	Short: "Vanadium-specific utilities for interacting with Jenkins",
	Long: `
Command vjenkins implements Vanadium-specific utilities for interacting with
Jenkins.
`,
	Children: []*cmdline.Command{cmdNode},
}

var cmdNode = &cmdline.Command{
	Name:     "node",
	Short:    "Manage Jenkins slave nodes",
	Long:     "Manage Jenkins slave nodes.",
	Children: []*cmdline.Command{cmdNodeCreate, cmdNodeDelete},
}

var cmdNodeCreate = &cmdline.Command{
	Runner: cmdline.RunnerFunc(runNodeCreate),
	Name:   "create",
	Short:  "Create Jenkins slave nodes",
	Long: `
Create Jenkins nodes. Uses the Jenkins REST API to create new slave nodes.
`,
	ArgsName: "<names>",
	ArgsLong: "<names> is a list of names identifying nodes to be created.",
}

var cmdNodeDelete = &cmdline.Command{
	Runner: cmdline.RunnerFunc(runNodeDelete),
	Name:   "delete",
	Short:  "Delete Jenkins slave nodes",
	Long: `
Delete Jenkins nodes. Uses the Jenkins REST API to delete existing slave nodes.
`,
	ArgsName: "<names>",
	ArgsLong: "<names> is a list of names identifying nodes to be deleted.",
}

var (
	flagCredentialsId string
	flagDescription   string
	flagJenkinsHost   string
	flagProject       string
	flagZone          string

	ipAddressRE = regexp.MustCompile(`^(\S*)\s*(\S*)\s(\S*)\s(\S*)\s(\S*)\s(\S*)$`)
)

func init() {
	cmdVJenkins.Flags.StringVar(&flagJenkinsHost, "jenkins", "http://localhost:8080/jenkins", "The host of the Jenkins master.")
	cmdNodeCreate.Flags.StringVar(&flagCredentialsId, "credentials-id", "73f76f53-8332-4259-bc08-d6f0b8521a5b", "The credentials ID used to connect the master to the node.")
	cmdNodeCreate.Flags.StringVar(&flagDescription, "description", "", "Node description.")
	cmdNodeCreate.Flags.StringVar(&flagZone, "zone", "us-central1-f", "GCE zone of the machine.")
	cmdNodeCreate.Flags.StringVar(&flagProject, "project", "vanadium-internal", "GCE project of the machine.")

	tool.InitializeRunFlags(&cmdVJenkins.Flags)
}

func newContext(env *cmdline.Env) *tool.Context {
	return tool.NewContextFromEnv(env)
}

// lookupIPAddress looks up the IP address for the given GCE node.
func lookupIPAddress(ctx *tool.Context, node string) (string, error) {
	var out bytes.Buffer
	if err := ctx.NewSeq().Capture(&out, ctx.Stderr()).Last("gcloud", "compute", "instances",
		"--project", flagProject,
		"list", "--zones", flagZone, "-r", node, "--format=json"); err != nil {
		return "", err
	}
	var instances []struct {
		Name              string
		NetworkInterfaces []struct {
			AccessConfigs []struct {
				NatIP string
			}
		}
	}
	if err := json.Unmarshal(out.Bytes(), &instances); err != nil {
		return "", fmt.Errorf("Unmarshal() failed: %v", err)
	}
	if len(instances) != 1 {
		return "", fmt.Errorf("unexpected output:\n%v", out.String())
	}
	instance := instances[0]
	return instance.NetworkInterfaces[0].AccessConfigs[0].NatIP, nil
}

// runNodeCreate adds slave node(s) to Jenkins configuration.
func runNodeCreate(env *cmdline.Env, args []string) error {
	ctx := newContext(env)
	jenkins, err := ctx.Jenkins(flagJenkinsHost)
	if err != nil {
		return err
	}

	for _, name := range args {
		ipAddress, err := lookupIPAddress(ctx, name)
		if err != nil {
			return err
		}
		fmt.Println(ipAddress)
		if err := jenkins.AddNodeToJenkins(name, ipAddress, flagDescription, flagCredentialsId); err != nil {
			return err
		}
	}
	return nil
}

// runNodeDelete removes slave node(s) from Jenkins configuration.
func runNodeDelete(env *cmdline.Env, args []string) error {
	ctx := newContext(env)
	jenkins, err := ctx.Jenkins(flagJenkinsHost)
	if err != nil {
		return err
	}

	for _, node := range args {
		// Wait for the node to become idle.
		const numRetries = 60
		const retryPeriod = time.Minute
		for i := 0; i < numRetries; i++ {
			if ok, err := jenkins.IsNodeIdle(node); err != nil {
				return err
			} else if ok {
				break
			}
			time.Sleep(retryPeriod)
		}
		err := jenkins.RemoveNodeFromJenkins(node)
		if err != nil {
			return err
		}
	}
	return nil
}
