package main

import (
	"flag"
	"fmt"
	"os"
	"strings"

	venvmanager "code.fbi.h-da.de/danet/gosdn/applications/venv-manager/venv-manager"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
)

func main() {
	var dialConnectionURL string
	var toplogyFilepath string
	var customContainerRegistryURL string
	var sdnConfigFilepath string
	var mode string

	dialOption := grpc.WithTransportCredentials(insecure.NewCredentials())

	flag.StringVar(&mode, "mode", "extract", "")
	flag.StringVar(&dialConnectionURL, "controller", "localhost:55055", "")
	flag.StringVar(&toplogyFilepath, "topology", "venv.clab.yaml", "")
	flag.StringVar(&customContainerRegistryURL, "registry", "", "")
	flag.StringVar(&sdnConfigFilepath, "sdnconfig", "sdn_config.json", "")

	// Define own output of --help and parsing error, as some library also uses the flags library and adds there flags to ours, which is not intended.
	flag.Usage = func() {
		fmt.Printf("Usable flags of the venv-manager:\n\n")
		fmt.Println("--mode string\n\t The mode of the venv-manager. use either 'extract', 'deploy' or 'apply'. (Default: 'extract')")
		fmt.Println("--controller string\n\t Controller URL and Port. (Default: 'localhost:55055')")
		fmt.Println("--topology string\n\t Filename of the resulting topology file. (Default: 'venv.clab.yaml')")
		fmt.Println("--sdnconfig string\n\t Filename of the resulting SDN configuration file. (Default: 'sdn_config.json')")
		fmt.Println("--registry string\n\t URL of the container registry to use. Keep in mind that cEOS images and prebuild linux images with the gnmi target are not available on dockerhub. (Default: none (dockerhub))")
		fmt.Println("--help\n\t Shows this help screen.")
	}
	flag.Parse()

	customContainerRegistryURL = ensureLastCharIsSlash(customContainerRegistryURL)

	fmt.Println("I will try to connect to goSDN located at:", dialConnectionURL)
	venvManager := venvmanager.NewVenvManager(dialConnectionURL, dialOption, toplogyFilepath, sdnConfigFilepath, customContainerRegistryURL)

	if mode == "extract" {
		fmt.Println("Generating topology file...")
		err := venvManager.CreateTopologyFile()
		if err != nil {
			printErrAndAbort(err)
		}

		fmt.Println("Generating SDN configuration file...")
		err = venvManager.CreateSDNConfigFile()
		if err != nil {
			printErrAndAbort(err)
		}
	} else if mode == "deploy" {
		fmt.Println("Creating environment... (This might take a long time and may require sudo rights and the password of the user)")
		err := venvManager.StartVirtualEnvironment()
		if err != nil {
			printErrAndAbort(err)
		}
		fmt.Println("Environment created.")

		fmt.Println("Applying SDN config to controller...")
		err = venvManager.ReadAndSendSDNConfig()
		if err != nil {
			printErrAndAbort(err)
		}
		fmt.Println("SDN config applied.")
		fmt.Println("To stop or restart the virtual environment interact with containerlab itself.\nFor more information visit their documentation: https://containerlab.dev/")
	} else if mode == "apply" {
		fmt.Println("Sending SDN config to controller...")
		err := venvManager.ReadAndSendSDNConfig()
		if err != nil {
			printErrAndAbort(err)
		}
		fmt.Println("SDN config applied.")
	} else {
		fmt.Println("No valid mode selected. Choose either 'extract', 'deploy' or 'apply'.")
	}

	fmt.Println("All done!")
	os.Exit(0)
}

// Ensures that the last char of a string is a slash, if this string is not empty.
func ensureLastCharIsSlash(inputString string) string {
	if len(inputString) == 0 {
		return inputString
	}

	if strings.HasSuffix(inputString, "/") {
		return inputString
	}

	return inputString + "/"
}

func printErrAndAbort(err error) {
	fmt.Println(err)
	fmt.Println("An error occurred, exiting.")
	os.Exit(1)
}
