// Copyright 2024 WIT.COM Inc Licensed GPL 3.0

package main

import (
	"embed"
	"fmt"
	"net/url"
	"os"
	"path/filepath"
	"time"

	"github.com/google/uuid"
	"go.wit.com/dev/alexflint/arg"
	"go.wit.com/gui"
	"go.wit.com/lib/protobuf/virtpb"
	"go.wit.com/lib/virtigolib"
	"go.wit.com/log"
)

var Version string

//go:embed resources/*
var resources embed.FS

func main() {
	var pp *arg.Parser
	gui.InitArg()
	pp = arg.MustParse(&argv)

	if pp == nil {
		pp.WriteHelp(os.Stdout)
		os.Exit(0)
	}

	if os.Getenv("VIRTIGO_HOME") == "" {
		homeDir, _ := os.UserHomeDir()
		fullpath := filepath.Join(homeDir, ".config/virtigo")
		os.Setenv("VIRTIGO_HOME", fullpath)
	}

	me.clusters = virtpb.NewClusters()

	if argv.Admin {
		err := me.clusters.ConfigLoad()
		if err != nil {
			badExit(err)
		}

		me.admin = new(adminT)
		me.admin.doAdminGui()
		okExit("admin close")
	}

	if argv.Server != "" {
		log.Info("start admin interface")
		me.admin = new(adminT)
		var err error
		me.admin.url, err = url.Parse(argv.Server)
		if err != nil {
			badExit(err)
		}
		err = me.clusters.ConfigLoad()
		if err != nil {
			clusters := virtpb.NewClusters()
			c := new(virtpb.Cluster)
			c.Uuid = uuid.New().String()
			c.URL = argv.Server
			clusters.Append(c)
			virtpb.ConfigWriteTEXT(clusters, "cluster.text")

			badExit(err)
		}

		me.admin.doAdminGui()
		okExit("admin close")
	}
	os.Exit(-1)

	// set defaults
	me.unstable = time.Now() // initialize the grid as unstable
	me.changed = false
	me.hmap = make(map[*virtpb.Hypervisor]*HyperT)

	// how long a droplet can be missing until it's declared dead
	me.unstableTimeout = 17 * time.Second
	me.missingDropletTimeout = time.Minute // not sure the difference between these values

	// how often to poll the hypervisors
	me.hyperPollDelay = 5 * time.Second

	// how long the cluster must be stable before new droplets can be started
	me.clusterStableDuration = 37 * time.Second

	me.cluster = virtpb.InitCluster()
	if err := me.cluster.ConfigLoad(); err != nil {
		log.Info("config load error", err)
		log.Info("")
		log.Info("You have never run this before")
		log.Info("init example cloud here")
		log.Sleep(2)
		os.Exit(-1)
	}

	loop := me.cluster.DropletsAll() // get the list of droplets
	for loop.Scan() {
		d := loop.Next()
		if d == nil {
			fmt.Println("d == nil")
			os.Exit(-1)
		}
		fmt.Println("Droplet UUID:", d.Uuid)
		if d.Current == nil {
			d.Current = new(virtpb.Current)
		}
		d.SetState(virtpb.DropletState_OFF)
		log.Info("droplet", d.Hostname)
	}
	hmm := "pihole.wit.com"
	d := me.cluster.FindDropletByName(hmm)
	if d == nil {
		log.Info("did not find found droplet", hmm)
	} else {
		log.Info("found droplet", d.Hostname, d)
	}

	var newEvents []*virtpb.Event

	// sanity check the cluster & droplets
	if _, _, err := ValidateDroplets(); err != nil {
		log.Info("todo: add flag to ignore. for now, fix problems in the config file.")
		os.Exit(0)
	}
	newe, err := ValidateDiskFilenames()
	if err != nil {
		log.Info(err)
		os.Exit(-1)
	}
	// this is a new droplet. add it to the cluster
	for _, e := range newe {
		newEvents = append(newEvents, e)
	}
	ValidateUniqueFilenames()

	for _, filename := range argv.Xml {
		domcfg, err := virtigolib.ReadXml(filename)
		if err != nil {
			// parsing the libvirt xml file failed
			log.Info("error:", filename, err)
			log.Info("readXml() error", filename)
			log.Info("readXml() error", err)
			log.Info("libvirt XML will have to be fixed by hand")
			os.Exit(-1)
		}
		// this is a new droplet. add it to the cluster
		log.Info("Add XML Droplet here", domcfg.Name)
		_, newe, err := virtigolib.AddDomainDroplet(me.cluster, domcfg)
		if err != nil {
			log.Info("addDomainDroplet() error", filename)
			log.Info("addDomainDroplet() error", err)
			log.Info("libvirt XML will have to be fixed by hand")
			os.Exit(-1)
		}
		for _, e := range newe {
			newEvents = append(newEvents, e)
		}
	}
	for i, e := range newEvents {
		log.Info(i, "Event:", e.Droplet, e.FieldName, "orig:", e.OrigVal, "new:", e.NewVal)
		me.changed = true
	}

	if me.changed {
		if err := me.cluster.ConfigSave(); err != nil {
			log.Info("configsave error", err)
			os.Exit(-1)
		}
		log.Info("XML changes saved in protobuf config")
		os.Exit(0)
	}
	if len(argv.Xml) != 0 {
		log.Info("No XML changes found")
		os.Exit(0)
	}

	// initialize each hypervisor
	for _, pbh := range me.cluster.H.Hypervisors {
		// this is a new unknown droplet (not in the config file)
		var h *HyperT
		h = new(HyperT)
		h.pb = pbh
		h.lastDroplets = make(map[string]time.Time)
		h.lastpoll = time.Now()

		me.hmap[pbh] = h
		me.hypers = append(me.hypers, h)
		log.Log(EVENT, "config new hypervisors", h.pb.Hostname)
	}

	// start the watchdog polling for each hypervisor
	for _, h := range me.hypers {
		log.Info("starting polling on", h.pb.Hostname)

		// start a watchdog on each hypervisor
		go h.NewWatchdog()
	}

	var cloud *virtigolib.CloudManager
	cloud = virtigolib.NewCloud()
	found, _ := cloud.FindDropletByName("www.wit.com")
	if found == nil {
		log.Info("d == nil")
	} else {
		log.Info("d == ", found)
	}

	// sit here
	go startHTTP()
	doGui()
}