package peer

import (
	"encoding/json"
	"fmt"
	"log"
	"net"
	"net/http"
	"net/netip"
	"os"
)

// Usage:
//
// vppn netName run
// vppn netName status
func Main2() {
	printUsage := func() {
		fmt.Fprintf(os.Stderr, `%s COMMAND [ARGUMENTS...]

Available commands:
    run
    status
`, os.Args[0])
		os.Exit(1)
	}

	if len(os.Args) < 2 {
		printUsage()
	}

	command := os.Args[1]

	switch command {
	case "run":
		main_run()
	case "status":
		main_status()
	default:
		printUsage()
	}
}

// ----------------------------------------------------------------------------

type mainArgs struct {
	NetName    string
	HubAddress string
	APIKey     string
}

func main_run() {
	printUsage := func() {
		fmt.Fprintf(os.Stderr, `Usage: %s run NETWORK_NAME HUB_ADDRESS API_KEY

    NETWORK_NAME
        Unique name of the network interface created. The network name
        shouldn't change between invocations of the application.

    HUB_ADDRESS
        The address of the hub server. This should also contain the scheme, for
        example https://hub.domain.com/.

    API_KEY
        The API key assigned to this peer by the hub.

`, os.Args[0])
		os.Exit(1)
	}

	if len(os.Args) != 5 {
		printUsage()
	}

	args := mainArgs{
		NetName:    os.Args[2],
		HubAddress: os.Args[3],
		APIKey:     os.Args[4],
	}

	newPeerMain(args).Run()
}

// ----------------------------------------------------------------------------

func main_status() {
	printUsage := func() {
		fmt.Fprintf(os.Stderr, `Usage: %s status NETWORK_NAME

    NETWORK_NAME
        Unique name of the network interface created.

`, os.Args[0])
		os.Exit(1)
	}

	if len(os.Args) != 3 {
		printUsage()
	}

	netName := os.Args[2]

	client := http.Client{
		Transport: &http.Transport{
			Dial: func(_, _ string) (net.Conn, error) {
				return net.Dial("unix", statusSocketPath(netName))
			},
		},
	}

	getURL := "http://unix" + statusSocketPath(netName)
	resp, err := client.Get(getURL)
	if err != nil {
		log.Fatalf("Failed to get response: %v", err)
	}

	report := StatusReport{}
	if err := json.NewDecoder(resp.Body).Decode(&report); err != nil {
		log.Fatalf("Failed to decode status report: %v", err)
	}

	fmt.Printf("\n%s Status\n\n", netName)

	if len(report.Network) != 4 {
		fmt.Printf("Network: %v\n\n", report.Network)
	} else {
		nw := report.Network
		fmt.Printf("%-8s %d.%d.%d.%d/24\n", "Network", nw[0], nw[1], nw[2], nw[3])
	}
	fmt.Printf("%-8s %d\n\n", "Relay", report.RelayPeerIP)

	for _, status := range report.Remotes {
		fmt.Printf("%3d %s\n", status.PeerIP, status.Name)
		fmt.Printf("    %-11s %v\n", "Up", status.Up)

		pubIP, ok := netip.AddrFromSlice(status.PublicIP)
		if ok {
			fmt.Printf("    %-11s %v\n", "Public IP", pubIP)
		} else {
			fmt.Printf("    %-11s\n", "Public IP")
		}
		fmt.Printf("    %-11s %d\n", "Port", status.Port)
		fmt.Printf("    %-11s %v\n", "Relay", status.Relay)
		fmt.Printf("    %-11s %v\n", "Server", status.Server)
		fmt.Printf("    %-11s %v\n", "Direct", status.Direct)
		if status.DirectAddr.IsValid() {
			fmt.Printf("    %-11s %v\n", "Address", status.DirectAddr)
		}
		fmt.Println("")
	}
}
