package nodestatus

import (
	"fmt"
	"os"
	"sort"
	"strings"
	"time"

	"github.com/fatih/color"
	apinode "github.com/hpcng/warewulf/internal/pkg/api/node"
	"github.com/hpcng/warewulf/internal/pkg/api/routes/wwapiv1"
	"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
	"github.com/hpcng/warewulf/internal/pkg/wwlog"
	"github.com/hpcng/warewulf/pkg/hostlist"
	"github.com/spf13/cobra"
	"golang.org/x/term"
)

func CobraRunE(cmd *cobra.Command, args []string) (err error) {

	controller, err := warewulfconf.New()
	if err != nil {
		wwlog.Error("%s\n", err)
		os.Exit(1)
	}

	if controller.Ipaddr == "" {
		wwlog.Error("The Warewulf Server IP Address is not properly configured\n")
		os.Exit(1)
	}

	for {
		var elipsis bool
		var height int
		var count int
		rightnow := time.Now().Unix()

		var nodeStatusResponse *wwapiv1.NodeStatusResponse
		nodeStatusResponse, err = apinode.NodeStatus([]string{})
		if err != nil {
			return err
		}

		if SetWatch {
			fmt.Print("\033[H\033[2J")
			_, height, err = term.GetSize(0)
			if err != nil {
				wwlog.Warn("Could not get terminal height, using 24\n")
				height = 24
			}
		}

		fmt.Printf("%-20s %-20s %-25s %-10s\n", "NODENAME", "STAGE", "SENT", "LASTSEEN (s)")
		fmt.Printf("%s\n", strings.Repeat("=", 80))

		wwlog.Verbose("Building sort index\n")
		var statuses []*wwapiv1.NodeStatus
		if len(args) > 0 {
			nodeList := hostlist.Expand(args)
			for i := 0; i < len(nodeStatusResponse.NodeStatus); i++ {
				for j := 0; j < len(nodeList); j++ {
					if nodeStatusResponse.NodeStatus[i].NodeName == nodeList[j] {
						statuses = append(statuses, nodeStatusResponse.NodeStatus[i])
						break
					}
				}
			}
		} else {
			for i := 0; i < len(nodeStatusResponse.NodeStatus); i++ {
				statuses = append(statuses, nodeStatusResponse.NodeStatus[i])
			}
		}

		wwlog.Verbose("Sorting index\n")
		if SetSortLast {
			sort.Slice(statuses, func(i, j int) bool {
				if statuses[i].Lastseen > statuses[j].Lastseen {
					return true
				} else if statuses[i].Lastseen < statuses[j].Lastseen {
					return false
				} else {
					return statuses[i].NodeName < statuses[j].NodeName
				}
			})
		} else if SetSortReverse {
			wwlog.Verbose("Reversing sort order\n")
			sort.Slice(statuses, func(i, j int) bool {
				return statuses[i].NodeName > statuses[j].NodeName
			})

		} else {
			sort.Slice(statuses, func(i, j int) bool {
				return statuses[i].NodeName < statuses[j].NodeName
			})
		}

		wwlog.Verbose("Printing results\n")
		for i := 0; i < len(statuses); i++ {
			o := statuses[i]
			if SetTime > 0 && o.Lastseen < SetTime {
				continue
			}

			if o.Lastseen > 0 {
				if SetUnknown {
					continue
				}
				if rightnow-o.Lastseen >= int64(controller.Warewulf.UpdateInterval*2) {
					color.Red("%-20s %-20s %-25s %-10d\n", o.NodeName, o.Stage, o.Sent, rightnow-o.Lastseen)
				} else if rightnow-o.Lastseen >= int64(controller.Warewulf.UpdateInterval+5) {
					color.Yellow("%-20s %-20s %-25s %-10d\n", o.NodeName, o.Stage, o.Sent, rightnow-o.Lastseen)
				} else {
					fmt.Printf("%-20s %-20s %-25s %-10d\n", o.NodeName, o.Stage, o.Sent, rightnow-o.Lastseen)
				}
			} else {
				color.HiBlack("%-20s %-20s %-25s %-10s\n", o.NodeName, "--", "--", "--")
			}
			if count+4 >= height && SetWatch {
				if count+1 != len(statuses) {
					elipsis = true
				}
				break
			}
			count++
		}

		if SetWatch {
			if elipsis {
				fmt.Printf("... ")
			}
			time.Sleep(time.Duration(SetUpdate) * time.Millisecond)
		} else {
			break
		}
	}
	return
}
