// 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.

package v23tests

import (
	"bytes"
	"io"
	"os"
	"strings"

	"v.io/x/ref/test/modules"
)

// Binary represents an executable program that will be executed during a
// test. A binary may be invoked multiple times by calling Start, each call
// will return a new Invocation.
//
// Binary instances are typically obtained from a T by calling BuldV23Pkg,
// BuildGoPkg (for Vanadium and other Go binaries) or BinaryFromPath (to
// start binaries that are already present on the system).
type Binary struct {
	// The environment to which this binary belongs.
	env *T

	// The path to the binary.
	path string

	// StartOpts
	opts modules.StartOpts

	// Environment variables that will be used when creating invocations
	// via Start.
	envVars []string

	// Optional prefix arguments are added to each invocation.
	prefixArgs []string
}

// StartOpts returns the current the StartOpts
func (b *Binary) StartOpts() modules.StartOpts {
	return b.opts
}

// Path returns the path to the binary.
func (b *Binary) Path() string {
	return b.path
}

// Start starts the given binary with the given arguments.
func (b *Binary) Start(args ...string) *Invocation {
	return b.start(1, args...)
}

func (b *Binary) start(skip int, oargs ...string) *Invocation {
	args := make([]string, len(b.prefixArgs), len(oargs)+len(b.prefixArgs))
	copy(args, b.prefixArgs)
	args = append(args, oargs...)
	b.env.ctx.Infof("%s: starting %s %s", Caller(skip+1), b.Path(), strings.Join(args, " "))
	opts := b.opts
	if opts.ExecProtocol && opts.Credentials == nil {
		opts.Credentials, opts.Error = b.env.shell.NewChildCredentials("child")
	}
	opts.ExpectTesting = b.env.TB
	handle, err := b.env.shell.StartWithOpts(opts, b.envVars, modules.Program(b.Path()), args...)
	if err != nil {
		if handle != nil {
			b.env.ctx.Infof("%s: start failed", Caller(skip+1))
			handle.Shutdown(nil, os.Stderr)
		}
		// TODO(cnicolaou): calling Fatalf etc from a goroutine often leads
		// to deadlock. Need to make sure that we handle this here. Maybe
		// it's best to just return an error? Or provide a StartWithError
		// call for use from goroutines.
		b.env.Fatalf("%s: StartWithOpts(%v, %v) failed: %v", Caller(skip+1), b.Path(), strings.Join(args, ", "), err)
	}
	b.env.ctx.Infof("started PID %d\n", handle.Pid())
	inv := &Invocation{
		env:           b.env,
		path:          b.path,
		args:          args,
		shutdownErr:   errNotShutdown,
		privateHandle: handle,
	}
	b.env.appendInvocation(inv)
	return inv
}

func (b *Binary) run(args ...string) string {
	inv := b.start(2, args...)
	var stdout, stderr bytes.Buffer
	err := inv.Wait(&stdout, &stderr)
	if err != nil {
		a := strings.Join(args, ", ")
		b.env.Fatalf("%s: Run(%s): failed: %v: \n%s\n", Caller(2), a, err, stderr.String())
	}
	return strings.TrimRight(stdout.String(), "\n")
}

// Run runs the binary with the specified arguments to completion. On
// success it returns the contents of stdout, on failure it terminates the
// test with an error message containing the error and the contents of
// stderr.
func (b *Binary) Run(args ...string) string {
	return b.run(args...)
}

// WithStdin returns a copy of this binary that, when Start is called,
// will read its input from the given reader. Once the reader returns
// EOF, the returned invocation's standard input will be closed (see
// Invocation.CloseStdin).
func (b *Binary) WithStdin(r io.Reader) *Binary {
	opts := b.opts
	opts.Stdin = r
	return b.WithStartOpts(opts)
}

// WithEnv returns a copy of this binary that, when Start is called, will use
// the given environment variables. Each environment variable should be
// in "key=value" form. For example:
//
// bin.WithEnv("EXAMPLE_ENV=/tmp/something").Start(...)
func (b *Binary) WithEnv(env ...string) *Binary {
	newBin := *b
	newBin.envVars = env
	return &newBin
}

// WithStartOpts eturns a copy of this binary that, when Start is called, will
// use the given StartOpts.
//
// bin.WithStartOpts(opts).Start(...)
// or
// bin.WithStartOpts().Run(...)
func (b *Binary) WithStartOpts(opts modules.StartOpts) *Binary {
	newBin := *b
	newBin.opts = opts
	return &newBin
}

// WithPrefixArgs returns a copy of this binary that, when Start or Run
// is called, will use the given additional arguments. For example: given
// a Binary b built from "git", then b2 := WithPrefixArgs("checkout")
// will let one run git checkout a; git checkout b with b2.Run("a"),
// b2.Run("b").
func (b *Binary) WithPrefixArgs(prefixArgs ...string) *Binary {
	newBin := *b
	newBin.prefixArgs = prefixArgs
	return &newBin
}
