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

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"testing"
	"time"

	"v.io/v23"
	"v.io/v23/context"
	"v.io/v23/rpc"
	"v.io/v23/security"
	"v.io/x/lib/vlog"
	"v.io/x/ref/lib/exec"
	"v.io/x/ref/lib/mgmt"
	"v.io/x/ref/lib/signals"
	"v.io/x/ref/services/device/internal/suid"
	"v.io/x/ref/test"
	"v.io/x/ref/test/modules"
	"v.io/x/ref/test/testutil"
)

const (
	TestFlagName = "random_test_flag"
)

var flagValue = flag.String(TestFlagName, "default", "")

func init() {
	// The installer sets this flag on the installed device manager, so we
	// need to ensure it's defined.
	flag.String("name", "", "")
}

// appService defines a test service that the test app should be running.
// TODO(caprita): Use this to make calls to the app and verify how Kill
// interacts with an active service.
type appService struct{}

func (appService) Echo(_ *context.T, _ rpc.ServerCall, message string) (string, error) {
	return message, nil
}

func (appService) Cat(_ *context.T, _ rpc.ServerCall, file string) (string, error) {
	if file == "" || file[0] == filepath.Separator || file[0] == '.' {
		return "", fmt.Errorf("illegal file name: %q", file)
	}
	bytes, err := ioutil.ReadFile(file)
	if err != nil {
		return "", err
	}
	return string(bytes), nil
}

type PingArgs struct {
	Username, FlagValue, EnvValue,
	DefaultPeerBlessings, PubBlessingPrefixes, InstanceName string
	Pid int
}

// ping makes a RPC from the App back to the invoking device manager
// carrying a PingArgs instance.
func ping(ctx *context.T, flagValue string) {

	ctx.Errorf("ping flagValue: %s", flagValue)

	helperEnv := os.Getenv(suid.SavedArgs)
	d := json.NewDecoder(strings.NewReader(helperEnv))
	var savedArgs suid.ArgsSavedForTest
	if err := d.Decode(&savedArgs); err != nil {
		ctx.Fatalf("Failed to decode preserved argument %v: %v", helperEnv, err)
	}
	args := &PingArgs{
		// TODO(rjkroege): Consider validating additional parameters
		// from helper.
		Username:             savedArgs.Uname,
		FlagValue:            flagValue,
		EnvValue:             os.Getenv(TestEnvVarName),
		Pid:                  os.Getpid(),
		DefaultPeerBlessings: v23.GetPrincipal(ctx).BlessingStore().ForPeer("nonexistent").String(),
	}

	if handle, err := exec.GetChildHandle(); err != nil {
		vlog.Fatalf("Couldn't get Child Handle: %v", err)
	} else {
		args.PubBlessingPrefixes, _ = handle.Config.Get(mgmt.PublisherBlessingPrefixesKey)
		args.InstanceName, _ = handle.Config.Get(mgmt.InstanceNameKey)
	}

	client := v23.GetClient(ctx)
	if call, err := client.StartCall(ctx, "pingserver", "Ping", []interface{}{args}); err != nil {
		ctx.Fatalf("StartCall failed: %v", err)
	} else if err := call.Finish(); err != nil {
		ctx.Fatalf("Finish failed: %v", err)
	}
}

// Cat is an RPC invoked from the test harness process to the application process.
func Cat(ctx *context.T, name, file string) (string, error) {
	ctx, cancel := context.WithTimeout(ctx, time.Minute)
	defer cancel()
	client := v23.GetClient(ctx)
	call, err := client.StartCall(ctx, name, "Cat", []interface{}{file})
	if err != nil {
		return "", err
	}
	var content string
	if err := call.Finish(&content); err != nil {
		return "", err
	}
	return content, nil
}

// App is a test application. It pings the invoking device manager with state information.
var App = modules.Register(appFunc, "App")

func appFunc(env *modules.Env, args ...string) error {
	ctx, shutdown := test.V23Init()
	defer shutdown()

	if expected, got := 1, len(args); expected != got {
		ctx.Fatalf("Unexpected number of arguments: expected %d, got %d", expected, got)
	}
	publishName := args[0]

	ctx, server, err := v23.WithNewServer(ctx, publishName, new(appService), nil)
	if err != nil {
		ctx.Fatalf("NewServer(%v) failed: %v", publishName, err)
	}
	WaitForMount(ctx, ctx, publishName, server)
	// Some of our tests look for log files, so make sure they are flushed
	// to ensure that at least the files exist.
	ctx.FlushLog()

	shutdownChan := signals.ShutdownOnSignals(ctx)
	ping(ctx, *flagValue)

	<-shutdownChan
	if err := ioutil.WriteFile("testfile", []byte("goodbye world"), 0600); err != nil {
		ctx.Fatalf("Failed to write testfile: %v", err)
	}
	return nil
}

type PingServer struct {
	ing chan PingArgs
}

// TODO(caprita): Set the timeout in a more principled manner.
const pingTimeout = 60 * time.Second

func (p PingServer) Ping(_ *context.T, _ rpc.ServerCall, arg PingArgs) error {
	p.ing <- arg
	return nil
}

// SetupPingServer creates a server listening for a ping from a child app; it
// returns a channel on which the app's ping message is returned, and a cleanup
// function.
func SetupPingServer(t *testing.T, ctx *context.T) (PingServer, func()) {
	pingCh := make(chan PingArgs, 1)
	ctx, server, err := v23.WithNewServer(ctx, "pingserver", PingServer{pingCh}, security.AllowEveryone())
	if err != nil {
		t.Fatalf("NewServer(%q, <dispatcher>) failed: %v", "pingserver", err)
	}
	WaitForMount(t, ctx, "pingserver", server)
	return PingServer{pingCh}, func() {
		if err := server.Stop(); err != nil {
			t.Fatalf("Stop() failed: %v", err)
		}
	}
}

func (p PingServer) WaitForPingArgs(t *testing.T) PingArgs {
	var args PingArgs
	select {
	case args = <-p.ing:
	case <-time.After(pingTimeout):
		t.Fatalf(testutil.FormatLogLine(2, "failed to get ping"))
	}
	return args
}

func (p PingServer) VerifyPingArgs(t *testing.T, username, flagValue, envValue string) PingArgs {
	args := p.WaitForPingArgs(t)
	if args.Username != username || args.FlagValue != flagValue || args.EnvValue != envValue {
		t.Fatalf(testutil.FormatLogLine(2, "got ping args %q, expected [username = %v, flag value = %v, env value = %v]", args, username, flagValue, envValue))
	}
	return args // Useful for tests that want to check other values in the PingArgs result
}

// HangingApp is the same as App, except that it does not exit properly after
// being stopped.
var HangingApp = modules.Register(func(env *modules.Env, args ...string) error {
	err := appFunc(env, args...)
	time.Sleep(24 * time.Hour)
	return err
}, "HangingApp")
