package commands

import (
	"fmt"
	"log"
	"os"
	"path"
	"runtime"

	"github.com/bravetools/bravetools/db"
	"github.com/bravetools/bravetools/platform"
	"github.com/bravetools/bravetools/shared"
	"github.com/spf13/cobra"
)

var hostInit = &cobra.Command{
	Use:   "init",
	Short: "Create a new Bravetools host",
	Long:  ``,
	Run:   serverInit,
}

var hostConfigPath, storage, ram, network, backendType string
var remoteBackend bool
var publicImageRemote string = shared.DefaultPublicImageRemote

func init() {
	includeInitFlags(hostInit)
}

func includeInitFlags(cmd *cobra.Command) {
	cmd.PersistentFlags().StringVarP(&hostConfigPath, "config", "c", "", "Path to the host configuration file [OPTIONAL]")
	cmd.PersistentFlags().StringVarP(&storage, "storage", "s", "12", "Host storage size in GB[OPTIONAL]. default: 12")
	cmd.PersistentFlags().StringVarP(&ram, "memory", "m", "4GB", "Host memory size [OPTIONAL]. default 4GB")
	cmd.PersistentFlags().StringVarP(&network, "network", "n", "", "Host network IP range [OPTIONAL]. default: randomly generate RFC1918 address")

	cmd.PersistentFlags().BoolVar(&remoteBackend, "remote", false, "whether backend is remote (will not be initialized)")
	cmd.PersistentFlags().StringVar(&publicImageRemote, "default_image_remote", publicImageRemote, "The default public image remote to check if a base image is public")
}

func serverInit(cmd *cobra.Command, args []string) {
	userHome, _ := os.UserHomeDir()

	if _, err := os.Stat(path.Join(userHome, shared.BraveHome)); !os.IsNotExist(err) {
		log.Fatal("$HOME/.bravetools directory exists. Run rm -r $HOME/.bravetools to create a fresh install")
	}

	hostOs := runtime.GOOS

	if !remoteBackend {
		switch hostOs {
		case "linux":
			backendType = "lxd"
		case "darwin":
			backendType = "multipass"
		case "windows":
			backendType = "multipass"
		default:
			err := deleteBraveHome(userHome)
			if err != nil {
				fmt.Println(err.Error())
			}
			log.Fatal("unsupported host OS: ", hostOs)
		}

		if network == "" {
			ip, err := shared.GenerateRandomRFC1919()
			if err != nil {
				log.Fatal(err.Error())
			}
			network = ip
		}
	} else {
		backendType = "remote"
	}

	// Create $HOME/.bravetools
	err := createBraveHome(userHome)
	if err != nil {
		log.Fatal(err.Error())
	}

	dbPath := path.Join(userHome, shared.BraveDB)

	log.Println("Initialising Bravetools unit database")
	_, err = os.Stat(dbPath)
	if os.IsNotExist(err) {
		err = db.InitDB(dbPath)

		if err != nil {
			if err := deleteBraveHome(userHome); err != nil {
				fmt.Println(err.Error())
			}
			log.Fatal("failed to initialize database: ", err)
		}
	}

	params := platform.HostConfig{
		Storage: storage,
		Ram:     ram,
		Network: network,
		Backend: backendType,
	}

	if hostConfigPath != "" {
		err = shared.CopyFile(hostConfigPath, path.Join(userHome, shared.PlatformConfig))
		if err != nil {
			if err := deleteBraveHome(userHome); err != nil {
				fmt.Println(err.Error())
			}
			log.Fatal(err)
		}
		loadConfig()
	} else {
		userHome, _ := os.UserHomeDir()
		platform.SetupHostConfiguration(params, userHome, publicImageRemote)
		loadConfig()
	}

	// Create default remotes
	imagesRemote := platform.Remote{
		Name:     "images",
		URL:      "https://images.lxd.canonical.com",
		Protocol: "simplestreams",
		Public:   true,
	}

	ubuntuRemote := platform.Remote{
		Name:     "ubuntu",
		URL:      "https://cloud-images.ubuntu.com/releases/",
		Protocol: "simplestreams",
		Public:   true,
	}

	ubuntuMinimalRemote := platform.Remote{
		Name:     "ubuntu-minimal",
		URL:      "https://cloud-images.ubuntu.com/minimal/releases/",
		Protocol: "simplestreams",
		Public:   true,
	}

	err = platform.SaveRemote(imagesRemote)
	if err != nil {
		log.Fatal(err)
	}
	err = platform.SaveRemote(ubuntuRemote)
	if err != nil {
		log.Fatal(err)
	}
	err = platform.SaveRemote(ubuntuMinimalRemote)
	if err != nil {
		log.Fatal(err)
	}

	if remoteBackend {
		fmt.Println("bravetools initialized - add a remote with `brave remote add local ...`")
		return
	}

	log.Println("Initialising Bravetools backend")
	err = backend.BraveBackendInit()
	if err != nil {
		if err := deleteBraveHome(userHome); err != nil {
			fmt.Println(err.Error())
		}

		log.Fatal("error initializing Bravetools backend: ", err)
	}

	loadConfig()

	if backendType == "multipass" {
		info, err := backend.Info()

		if err != nil {
			if err := deleteBraveHome(userHome); err != nil {
				fmt.Println(err.Error())
			}
			log.Fatal(err)
		}

		settings := host.Settings
		if hostOs == "windows" {
			settings.BackendSettings.Resources.IP = info.Name + ".mshome.net"
		} else {
			settings.BackendSettings.Resources.IP = info.IPv4
		}
		err = platform.UpdateBraveSettings(settings)

		if err != nil {
			if err := deleteBraveHome(userHome); err != nil {
				fmt.Println(err.Error())
			}
			log.Fatal(err)
		}

		loadConfig()
	}

	log.Println("Registering a Remote")
	host.Remote = platform.NewBravehostRemote(host.Settings)
	err = platform.SaveRemote(host.Remote)
	if err != nil {
		if err := deleteBraveHome(userHome); err != nil {
			fmt.Println(err.Error())
		}
		log.Fatal("failed to save default bravetools remote: ", err)
	}
	err = host.AddRemote()
	if err != nil {
		if err := deleteBraveHome(userHome); err != nil {
			fmt.Println(err.Error())
		}
		log.Fatal(err)
	}
}
