package main

import (
	"flag"
	"fmt"
	"os"
)

func usage() {
	msg := `gke-iap: a gcloud wrapper to access GKE private cluster through IAP

Usage: gke-iap [Options...]
Options:
    -p,   -project              The Google Cloud project ID to use for this invocation.
    -c,   -cluster              Name of the GKE cluster. Default: default.
    -ip,  -instance-port        The number of the GKE instance's port to connect to.
                                Default: 30443.
    -lp,  -local-port           The number of the port on which should listen for
                                connections that should be tunneled. Default: 6443.
    -v,   -version              Show version information.
    -h,   -help                 Show help message.

Author:
    Raman Antanevich <r.antanevich@gmail.com>
    <https://github.com/rantanevich>
`
	fmt.Printf(msg)
}

type Options struct {
	ProjectID    string
	ClusterName  string
	InstancePort int
	LocalPort    int
}

func ParseOptions(versionInfo string) *Options {
	opts := &Options{}

	var version bool

	flag.StringVar(&opts.ProjectID, "p", "", "Google Cloud project ID")
	flag.StringVar(&opts.ProjectID, "project", "", "Google Cloud project ID")
	flag.StringVar(&opts.ClusterName, "c", "default", "Name of the GKE cluster")
	flag.StringVar(&opts.ClusterName, "cluster", "default", "Name of the GKE cluster")
	flag.IntVar(&opts.InstancePort, "ip", 30443, "The number of the GKE instance's port to connect to")
	flag.IntVar(&opts.InstancePort, "instance-port", 30443, "The number of the GKE instance's port to connect to")
	flag.IntVar(&opts.LocalPort, "lp", 6443, "The local port on which gcloud should listen for connections that should be tunneled")
	flag.IntVar(&opts.LocalPort, "local-port", 6443, "The local port on which gcloud should listen for connections that should be tunneled")
	flag.BoolVar(&version, "v", false, "Show version information")
	flag.BoolVar(&version, "version", false, "Show version information")
	flag.Usage = usage
	flag.Parse()

	if version {
		fmt.Println(versionInfo)
		os.Exit(0)
	}

	errMsg := opts.check()
	if len(errMsg) == 1 {
		fmt.Fprintf(os.Stderr, "Config error: %s\n", errMsg[0])
		os.Exit(1)
	} else if len(errMsg) > 1 {
		fmt.Fprintln(os.Stderr, "Config error:")
		for i, msg := range errMsg {
			fmt.Fprintf(os.Stderr, "%d. %s\n", i+1, msg)
		}
		os.Exit(1)
	}

	return opts
}

func (o *Options) check() (errMsg []string) {
	defaultProject := GetActiveProject()
	if o.ProjectID == "" && defaultProject == "" {
		errMsg = append(errMsg, "-p, -project: must be specified")
	} else if o.ProjectID == "" && defaultProject != "" {
		o.ProjectID = defaultProject
	}

	if o.ClusterName == "" {
		errMsg = append(errMsg, "-c, -cluster: cannot be empty")
	}

	if o.InstancePort > 65535 || o.InstancePort <= 0 {
		errMsg = append(errMsg, "Available INSTANCE_PORT range is 1-65535")
	}

	if o.LocalPort > 65535 || o.LocalPort < 0 {
		errMsg = append(errMsg, "Available LOCAL_PORT range is 0-65535")
	}

	return
}