package main

import (
	"context"
	"flag"
	"fmt"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/genuinetools/pkg/cli"
	"github.com/genuinetools/reg/registry"
	"github.com/genuinetools/reg/repoutils"
	"github.com/genuinetools/reg/version"
	"github.com/sirupsen/logrus"
)

var (
	insecure    bool
	forceNonSSL bool
	skipPing    bool

	timeout time.Duration

	authURL  string
	username string
	password string

	debug bool
)

//go:generate go run internal/binutils/generate.go
func main() {
	// Create a new cli program.
	p := cli.NewProgram()
	p.Name = "reg"
	p.Description = "Docker registry v2 client"
	// Set the GitCommit and Version.
	p.GitCommit = version.GITCOMMIT
	p.Version = version.VERSION

	// Build the list of available commands.
	p.Commands = []cli.Command{
		&digestCommand{},
		&layerCommand{},
		&listCommand{},
		&manifestCommand{},
		&removeCommand{},
		&serverCommand{},
		&tagsCommand{},
		&vulnsCommand{},
	}

	// Setup the global flags.
	p.FlagSet = flag.NewFlagSet("global", flag.ExitOnError)
	p.FlagSet.BoolVar(&insecure, "insecure", false, "do not verify tls certificates")
	p.FlagSet.BoolVar(&insecure, "k", false, "do not verify tls certificates")

	p.FlagSet.BoolVar(&forceNonSSL, "force-non-ssl", false, "force allow use of non-ssl")
	p.FlagSet.BoolVar(&forceNonSSL, "f", false, "force allow use of non-ssl")

	p.FlagSet.BoolVar(&skipPing, "skip-ping", false, "skip pinging the registry while establishing connection")

	p.FlagSet.DurationVar(&timeout, "timeout", time.Minute, "timeout for HTTP requests")

	p.FlagSet.StringVar(&authURL, "auth-url", "", "alternate URL for registry authentication (ex. auth.docker.io)")

	p.FlagSet.StringVar(&username, "username", "", "username for the registry")
	p.FlagSet.StringVar(&username, "u", "", "username for the registry")

	p.FlagSet.StringVar(&password, "password", "", "password for the registry")
	p.FlagSet.StringVar(&password, "p", "", "password for the registry")

	p.FlagSet.BoolVar(&debug, "d", false, "enable debug logging")

	// Set the before function.
	p.Before = func(ctx context.Context) error {
		// On ^C, or SIGTERM handle exit.
		signals := make(chan os.Signal)
		signal.Notify(signals, os.Interrupt)
		signal.Notify(signals, syscall.SIGTERM)
		_, cancel := context.WithCancel(ctx)
		go func() {
			for sig := range signals {
				cancel()
				logrus.Infof("Received %s, exiting.", sig.String())
				os.Exit(0)
			}
		}()

		// Set the log level.
		if debug {
			logrus.SetLevel(logrus.DebugLevel)
		}

		return nil
	}

	// Run our program.
	p.Run()
}

func createRegistryClient(ctx context.Context, domain string) (*registry.Registry, error) {
	// Use the auth-url domain if provided.
	authDomain := authURL
	if authDomain == "" {
		authDomain = domain
	}
	auth, err := repoutils.GetAuthConfig(username, password, authDomain)
	if err != nil {
		return nil, err
	}

	// Prevent non-ssl unless explicitly forced
	if !forceNonSSL && strings.HasPrefix(auth.ServerAddress, "http:") {
		return nil, fmt.Errorf("attempted to use insecure protocol! Use force-non-ssl option to force")
	}

	// Create the registry client.
	logrus.Infof("domain: %s", domain)
	logrus.Infof("server address: %s", auth.ServerAddress)
	return registry.New(ctx, auth, registry.Opt{
		Domain:   domain,
		Insecure: insecure,
		Debug:    debug,
		SkipPing: skipPing,
		NonSSL:   forceNonSSL,
		Timeout:  timeout,
	})
}
