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

import (
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"v.io/v23/naming"
	"v.io/v23/security"
	"v.io/v23/security/access"
	"v.io/v23/services/application"
	"v.io/v23/services/permissions"
	"v.io/v23/verror"

	"v.io/x/lib/cmdline"
	"v.io/x/ref/services/internal/binarylib"
	"v.io/x/ref/services/repository"
)

// TODO(caprita): Add unit test.

// TODO(caprita): Extend to include env, args, packages.

var cmdPublish = &cmdline.Command{
	Run:   runPublish,
	Name:  "publish",
	Short: "Publish the given application(s).",
	Long: `
Publishes the given application(s) to the binary and application servers.
The binaries should be in $V23_ROOT/release/go/bin/[<GOOS>_<GOARCH>].
The binary is published as <binserv>/<binary name>/<GOOS>-<GOARCH>/<TIMESTAMP>.
The application envelope is published as <appserv>/<binary name>/0.
Optionally, adds blessing patterns to the Read and Resolve AccessLists.`,
	ArgsName: "<binary name> ...",
}

var binaryService, applicationService, readBlessings, goarchFlag, goosFlag string

func init() {
	cmdPublish.Flags.StringVar(&binaryService, "binserv", "binaries", "Name of binary service.")
	cmdPublish.Flags.StringVar(&applicationService, "appserv", "applications", "Name of application service.")
	cmdPublish.Flags.StringVar(&goosFlag, "goos", runtime.GOOS, "GOOS for application.  The default is the value of runtime.GOOS.")
	cmdPublish.Flags.Lookup("goos").DefValue = "<runtime.GOOS>"
	cmdPublish.Flags.StringVar(&goarchFlag, "goarch", runtime.GOARCH, "GOARCH for application.  The default is the value of runtime.GOARCH.")
	cmdPublish.Flags.Lookup("goarch").DefValue = "<runtime.GOARCH>"
	cmdPublish.Flags.StringVar(&readBlessings, "readers", "dev.v.io", "If non-empty, comma-separated blessing patterns to add to Read and Resolve AccessList.")
}

func setAccessLists(cmd *cmdline.Command, von string) error {
	if readBlessings == "" {
		return nil
	}
	perms, version, err := permissions.ObjectClient(von).GetPermissions(gctx)
	if err != nil {
		// TODO(caprita): This is a workaround until we sort out the
		// default AccessLists for applicationd (see issue #1317).  At that
		// time, uncomment the line below.
		//
		//   return err
		perms = make(access.Permissions)
	}
	for _, blessing := range strings.Split(readBlessings, ",") {
		for _, tag := range []access.Tag{access.Read, access.Resolve} {
			perms.Add(security.BlessingPattern(blessing), string(tag))
		}
	}
	if err := permissions.ObjectClient(von).SetPermissions(gctx, perms, version); err != nil {
		return err
	}
	fmt.Fprintf(cmd.Stdout(), "Added patterns %q to Read,Resolve AccessList for %q\n", readBlessings, von)
	return nil
}

func publishOne(cmd *cmdline.Command, binPath, binaryName string) error {
	// Step 1, upload the binary to the binary service.

	// TODO(caprita): Instead of the current timestamp, use each binary's
	// BuildTimestamp from the buildinfo.
	timestamp := time.Now().UTC().Format(time.RFC3339)
	binaryVON := naming.Join(binaryService, binaryName, fmt.Sprintf("%s-%s", goosFlag, goarchFlag), timestamp)
	binaryFile := filepath.Join(binPath, binaryName)
	// TODO(caprita): Take signature of binary and put it in the envelope.
	if _, err := binarylib.UploadFromFile(gctx, binaryVON, binaryFile); err != nil {
		return err
	}
	fmt.Fprintf(cmd.Stdout(), "Binary %q uploaded from file %s\n", binaryVON, binaryFile)

	// Step 2, set the perms for the uploaded binary.

	if err := setAccessLists(cmd, binaryVON); err != nil {
		return err
	}

	// Step 3, download existing envelope (or create a new one), update, and
	// upload to application service.

	// TODO(caprita): use the profile detection machinery and/or let user
	// specify profiles by hand.
	profiles := []string{fmt.Sprintf("%s-%s", goosFlag, goarchFlag)}
	// TODO(caprita): use a label e.g. "prod" instead of "0".
	appVON := naming.Join(applicationService, binaryName, "0")
	appClient := repository.ApplicationClient(appVON)
	// NOTE: If profiles contains more than one entry, this will return only
	// the first match.  But presumably that's ok, since we're going to set
	// the envelopes for all the profiles to the same envelope anyway below.
	envelope, err := appClient.Match(gctx, profiles)
	if verror.ErrorID(err) == verror.ErrNoExist.ID {
		// There was nothing published yet, create a new envelope.
		envelope = application.Envelope{Title: binaryName}
	} else if err != nil {
		return err
	}
	envelope.Binary.File = binaryVON
	if err := repository.ApplicationClient(appVON).Put(gctx, profiles, envelope); err != nil {
		return err
	}
	fmt.Fprintf(cmd.Stdout(), "Published %q\n", appVON)

	// Step 4, set the perms for the uploaded envelope.

	if err := setAccessLists(cmd, appVON); err != nil {
		return err
	}
	return nil
}

func runPublish(cmd *cmdline.Command, args []string) error {
	if expectedMin, got := 1, len(args); got < expectedMin {
		return cmd.UsageErrorf("publish: incorrect number of arguments, expected at least %d, got %d", expectedMin, got)
	}
	binaries := args
	vroot := os.Getenv("V23_ROOT")
	if vroot == "" {
		return cmd.UsageErrorf("publish: $V23_ROOT environment variable should be set")
	}
	binPath := filepath.Join(vroot, "release/go/bin")
	if goosFlag != runtime.GOOS || goarchFlag != runtime.GOARCH {
		binPath = filepath.Join(binPath, fmt.Sprintf("%s_%s", goosFlag, goarchFlag))
	}
	if fi, err := os.Stat(binPath); err != nil {
		return cmd.UsageErrorf("publish: failed to stat %v: %v", binPath, err)
	} else if !fi.IsDir() {
		return cmd.UsageErrorf("publish: %v is not a directory", binPath)
	}
	if binaryService == "" {
		return cmd.UsageErrorf("publish: --binserv must point to a binary service name")
	}
	if applicationService == "" {
		return cmd.UsageErrorf("publish: --appserv must point to an application service name")
	}
	var lastErr error
	for _, b := range binaries {
		if err := publishOne(cmd, binPath, b); err != nil {
			fmt.Fprintf(cmd.Stderr(), "Failed to publish %q: %v\n", b, err)
			lastErr = err
		}
	}
	return lastErr
}
