// Copyright 2018 The Fuchsia 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 main

import (
	"context"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"

	"fuchsia.googlesource.com/tools/build"
	"fuchsia.googlesource.com/tools/qemu"
	"fuchsia.googlesource.com/tools/secrets"
	"github.com/google/subcommands"
)

// QEMUBinPrefix is the prefix of the QEMU binary name, which is of the form
// qemu-system-<QEMU arch suffix>.
const qemuBinPrefix = "qemu-system"

// QEMUCommand is a Command implementation for running the testing workflow on an emulated
// target within QEMU.
type QEMUCommand struct {
	// ImageManifest is the path an image manifest specifying a QEMU kernel, a zircon
	// kernel, and block image to back QEMU storage.
	imageManifest string

	// QEMUBinDir is a path to a directory of QEMU binaries.
	qemuBinDir string

	// MinFSImage is a path to a minFS image to be mounted on target, and to where test
	// results will be written.
	minFSImage string

	// MinFSBlkDevPCIAddr is a minFS block device PCI address.
	minFSBlkDevPCIAddr string

	// TargetArch is the target architecture to be emulated within QEMU
	targetArch string

	// EnableKVM dictates whether to enable KVM.
	enableKVM bool

	// EnableNetworking dictates whether to enable external networking.
	enableNetworking bool
}

func (*QEMUCommand) Name() string {
	return "qemu"
}

func (*QEMUCommand) Usage() string {
	return "qemu [flags...] [kernel command-line arguments...]\n\nflags:\n"
}

func (*QEMUCommand) Synopsis() string {
	return "boots a QEMU device with a MinFS image as a block device."
}

func (cmd *QEMUCommand) SetFlags(f *flag.FlagSet) {
	f.StringVar(&cmd.imageManifest, "images", "", "path to an image manifest")
	f.StringVar(&cmd.qemuBinDir, "qemu-dir", "", "")
	f.StringVar(&cmd.minFSImage, "minfs", "", "path to minFS image")
	f.StringVar(&cmd.minFSBlkDevPCIAddr, "pci-addr", "06.0", "minFS block device PCI address")
	f.StringVar(&cmd.targetArch, "arch", "", "target architecture (x64 or arm64)")
	f.BoolVar(&cmd.enableKVM, "use-kvm", false, "whether to enable KVM")
	f.BoolVar(&cmd.enableNetworking, "enable-networking", false, "whether to enable external networking")
}

func (cmd *QEMUCommand) execute(ctx context.Context, cmdlineArgs []string) error {
	if cmd.qemuBinDir == "" {
		return fmt.Errorf("-qemu-dir must be set")
	}

	imgs, err := build.LoadImages(cmd.imageManifest)
	if err != nil {
		return err
	}

	qemuCPU, ok := map[string]string{
		"x64":   "x86_64",
		"arm64": "aarch64",
	}[cmd.targetArch]
	if !ok {
		return fmt.Errorf("cpu %q not recognized", cmd.targetArch)
	}
	qemuBinPath := filepath.Join(cmd.qemuBinDir, fmt.Sprintf("%s-%s", qemuBinPrefix, qemuCPU))

	cfg := qemu.Config{
		QEMUBin:        qemuBinPath,
		CPU:            cmd.targetArch,
		KVM:            cmd.enableKVM,
		MinFSImage:     cmd.minFSImage,
		PCIAddr:        cmd.minFSBlkDevPCIAddr,
		InternetAccess: cmd.enableNetworking,
	}

	// The system will halt on a kernel panic instead of rebooting
	cmdlineArgs = append(cmdlineArgs, "kernel.halt-on-panic=true")
	// Print a message if `dm poweroff` times out.
	cmdlineArgs = append(cmdlineArgs, "devmgr.suspend-timeout-debug=true")
	// Do not print colors.
	cmdlineArgs = append(cmdlineArgs, "TERM=dumb")
	if cmd.targetArch == "x64" {
		// Necessary to redirect to stdout.
		cmdlineArgs = append(cmdlineArgs, "kernel.serial=legacy")
	}

	invocation, err := qemu.CreateInvocation(cfg, imgs, cmdlineArgs)
	if err != nil {
		return err
	}

	// The QEMU command needs to be invoked within an empty directory, as QEMU will attempt
	// to pick up files from its working directory, one notable culprit being multiboot.bin.
	// This can result in strange behavior.
	qemuWorkingDir, err := ioutil.TempDir("", "qemu-working-dir")
	if err != nil {
		return err
	}
	defer os.RemoveAll(qemuWorkingDir)

	qemuCmd := exec.Cmd{
		Path:   invocation[0],
		Args:   invocation,
		Dir:    qemuWorkingDir,
		Stdout: os.Stdout,
		Stderr: os.Stderr,
	}
	log.Printf("QEMU invocation:\n%s", invocation)
	return qemu.CheckExitCode(qemuCmd.Run())
}

func (cmd *QEMUCommand) Execute(ctx context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
	// TODO(IN-607) Once the secrets pipeline is supported on hardware, move the starting
	// of the secrets server to botanist's main().
	//
	// The secrets server will start up iff LUCI_CONTEXT is set and contains secret bytes.
	secrets.StartSecretsServer(ctx, 8081)

	if err := cmd.execute(ctx, f.Args()); err != nil {
		log.Print(err)
		return subcommands.ExitFailure
	}
	return subcommands.ExitSuccess
}
