package main

import (
	pb "code.fbi.h-da.de/cocsn/gosdn/cliInterface"
	"context"
	"flag"
	"fmt"
	"github.com/rivo/tview"
	"google.golang.org/grpc"
	"log"
	"os"
	"time"
)

const (
	address     = "localhost:55055"
	defaultName = "gosdn-cli"
)

// Based on the helloworld example of grpc.io -- thx!

const refreshInterval = 500 * time.Millisecond

var (
	view *tview.Modal
	app  *tview.Application
)

type cliClientConfig struct {
	goSDNCLIAddr4 *string
	goSDNCLIPort4 *int
	interactive   *bool
	goSDNCommand  *string
}

type commandOptions struct {
	name        string
	description string
	command     func(conn *grpc.ClientConn)
}

var commandList = map[string]commandOptions{
	"hello":    {"hello", "test connection to goSDN controller", goSDNSayHello},
	"shutdown": {"shutdown", "request goSDN controller to shutdown", goSDNShutdown},
	"testdb" :  {"testdb", "test all database connections", goSDNTestDB},
	"tapigetnodes" :  {"testdb", "test all database connections", goSDNTestDB},
}

/*
	gosdn-cli allows to mode of operations:
	- interactive: text GUI to operate goSDN
    - non-interactive: basic CLI without text GUI
*/

func main() {
	// This holds the basic configuration for gosdn-cli
	var myConfiguration = new(cliClientConfig)

	myConfiguration.goSDNCLIAddr4 = flag.String("cliServerAddr", "127.0.0.1", "The IPv4 Address of the grpcCLI.")
	myConfiguration.goSDNCLIPort4 = flag.Int("cliServerPort", 55055, "The port number of the grpcCLI")
	myConfiguration.interactive = flag.Bool("interactive", false, "interactive: text gui or just not")
	var printCommandList = flag.Bool("commandlist", false, "interactive: print command list")
	myConfiguration.goSDNCommand = flag.String("command", "", "-command: <your command> ; show commands with -commandlist")

	flag.Parse()

	// Print complete command list and exit
	if *printCommandList == true {
		for _, element := range commandList {
			fmt.Println(element.name + "\t" + element.description)
		}
		os.Exit(0)
	}

	log.Println("Starting " + defaultName + " to access the goSDN controller")
	// Prepare string with socket for connection to the goSDN controller
	goSDNSocketAddress := fmt.Sprintf("%s:%d", *myConfiguration.goSDNCLIAddr4, *myConfiguration.goSDNCLIPort4)

	log.Println("Connecting to the goSDN server at: " + goSDNSocketAddress)
	// Set up a connection to the server.
	address := "localhost:55055"

	conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBlock())
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	defer conn.Close()
	log.Println(("Connected to " + conn.Target()))

	// Check for non-interactive or interactive mode
	if *myConfiguration.interactive == false {
		log.Println("starting in non-interactive mode")
		// Lookup command or die
		_, found := commandList[*myConfiguration.goSDNCommand]
		if found {
			// Excecute desired command
			commandList[*myConfiguration.goSDNCommand].command(conn)
		} else {
			log.Fatalf("Your desired command %s is not available", commandList[*myConfiguration.goSDNCommand].name)
			os.Exit(1)
		}

	} else {
		log.Println("starting in interactive mode -- do not use yet")
		os.Exit(1)

		app = tview.NewApplication().EnableMouse(true)

		flex := tview.NewFlex().
			AddItem(tview.NewBox().SetBorder(true).SetTitle("Command List"), 0, 1, false).
			AddItem(tview.NewFlex().SetDirection(tview.FlexRow).
				AddItem(tview.NewBox().SetBorder(true).SetTitle("Top"), 0, 1, false).
				AddItem(tview.NewBox().SetBorder(true).SetTitle("Middle (3 x height of Top)"), 0, 3, false).
				AddItem(tview.NewBox().SetBorder(true).SetTitle("Bottom (5 rows)"), 5, 1, false), 0, 2, false)

		if err := app.SetRoot(flex, true).Run(); err != nil {
			panic(err)
		}
	}
}

func goSDNSayHello(conn *grpc.ClientConn) {

func goSDNSayHello (conn *grpc.ClientConn) {
	c := pb.NewGrpcCliClient(conn)

	// Contact the server and print out its response.
	name := defaultName
	if len(os.Args) > 1 {
		name = os.Args[1]
	}
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name})
	if err != nil {
		log.Fatalf("could not say hello: %v", err)
	}
	log.Printf("Greeting: %s", r.String())

}

func goSDNShutdown(conn *grpc.ClientConn) {

	c := pb.NewGrpcCliClient(conn)

	// Contact the server and print out its response.
	name := defaultName
	if len(os.Args) > 1 {
		name = os.Args[0]
	}
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	r, err := c.Shutdown(ctx, &pb.ShutdownRequest{Name: name})
	if err != nil {
		log.Fatalf("could not request shutdown: %v", err)
	}
	log.Printf("Greeting: %s", r.GetMessage())
}

func goSDNTestDB(conn *grpc.ClientConn) {
	// TODO: fill with code
}