package server

import (
	"context"
	"errors"
	"fmt"
	"net"
	"time"

	"coopcloud.tech/abra/cli/internal"
	"coopcloud.tech/abra/client"
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/swarm"
	"github.com/sirupsen/logrus"
	"github.com/urfave/cli/v2"
)

var serverInitCommand = &cli.Command{
	Name:      "init",
	Usage:     "Initialise server for deploying apps",
	HideHelp:  true,
	ArgsUsage: "<host>",
	Description: `
Initialise swarm mode on the target <host>.

This initialisation explicitly chooses the "single host swarm" mode which uses
the default IPv4 address as the advertising address. This can be re-configured
later for more advanced use cases.
`,
	Action: func(c *cli.Context) error {
		host := c.Args().First()
		if host == "" {
			internal.ShowSubcommandHelpAndError(c, errors.New("no host provided"))
		}

		cl, err := client.NewClientWithContext(host)
		if err != nil {
			return err
		}

		resolver := &net.Resolver{
			PreferGo: false,
			Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
				d := net.Dialer{
					Timeout: time.Millisecond * time.Duration(10000),
				}
				// comrade librehosters DNS resolver https://snopyta.org/service/dns/
				return d.DialContext(ctx, "udp", "95.216.24.230:53")
			},
		}

		ctx := context.Background()
		ips, err := resolver.LookupIPAddr(ctx, host)
		if err != nil {
			logrus.Fatal(err)
		}

		if len(ips) == 0 {
			return fmt.Errorf("unable to retrieve ipv4 address for %s", host)
		}
		ipv4 := ips[0].IP.To4().String()

		initReq := swarm.InitRequest{
			ListenAddr:    "0.0.0.0:2377",
			AdvertiseAddr: ipv4,
		}
		if _, err := cl.SwarmInit(ctx, initReq); err != nil {
			return err
		}

		netOpts := types.NetworkCreate{Driver: "overlay", Scope: "swarm"}
		if _, err := cl.NetworkCreate(ctx, "proxy", netOpts); err != nil {
			return err
		}

		return nil
	},
}