// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package command

import (
	"fmt"
	"sort"

	"github.com/hashicorp/nomad/api"
	"github.com/mitchellh/cli"
)

func deviceQualifiedID(vendor, typ, name, id string) string {
	p := vendor
	if typ != "" {
		p += "/" + typ
	}
	if name != "" {
		p += "/" + name
	}

	return p + "[" + id + "]"
}

func buildDeviceStatsSummaryMap(deviceGroupStats []*api.DeviceGroupStats) map[string]*api.StatValue {
	r := map[string]*api.StatValue{}

	for _, dg := range deviceGroupStats {
		for id, stats := range dg.InstanceStats {
			k := deviceQualifiedID(dg.Vendor, dg.Type, dg.Name, id)
			r[k] = stats.Summary
		}
	}

	return r
}

func formatDeviceStats(qid string, stat *api.StatObject) []string {
	attrs := []string{fmt.Sprintf("Device|%s", qid)}
	formatDeviceStatsImpl(stat, "", &attrs)

	sort.Strings(attrs[1:])

	return attrs
}

func formatDeviceStatsImpl(stat *api.StatObject, keyPrefix string, result *[]string) {
	if keyPrefix != "" {
		keyPrefix = keyPrefix + "."
	}

	for n, stat := range stat.Attributes {
		*result = append(*result, fmt.Sprintf("%s%s|%s", keyPrefix, n, stat))
	}

	for k, o := range stat.Nested {
		formatDeviceStatsImpl(o, keyPrefix+k, result)
	}
}

// getDeviceResourcesForNode returns a list of devices and their statistics summary
// and tracks devices without statistics
func getDeviceResourcesForNode(deviceGroupStats []*api.DeviceGroupStats, node *api.Node) []string {
	statsSummaryMap := buildDeviceStatsSummaryMap(deviceGroupStats)

	devices := []string{}
	for _, dg := range node.NodeResources.Devices {
		for _, inst := range dg.Instances {
			id := deviceQualifiedID(dg.Vendor, dg.Type, dg.Name, inst.ID)
			statStr := ""
			if stats, ok := statsSummaryMap[id]; ok && stats != nil {
				statStr = stats.String()
			}

			devices = append(devices, fmt.Sprintf("%v|%v", id, statStr))
		}
	}

	sort.Strings(devices)

	return devices
}

// getDeviceResources returns alist of devices and their statistics summary
func getDeviceResources(deviceGroupStats []*api.DeviceGroupStats) []string {
	statsSummaryMap := buildDeviceStatsSummaryMap(deviceGroupStats)

	result := make([]string, 0, len(statsSummaryMap))
	for id, stats := range statsSummaryMap {
		result = append(result, id+"|"+stats.String())
	}

	sort.Strings(result)

	return result
}

func printDeviceStats(ui cli.Ui, deviceGroupStats []*api.DeviceGroupStats) {
	isFirst := true
	for _, dg := range deviceGroupStats {
		for id, dinst := range dg.InstanceStats {
			if !isFirst {
				ui.Output("")
			}
			isFirst = false

			qid := deviceQualifiedID(dg.Vendor, dg.Type, dg.Name, id)
			attrs := formatDeviceStats(qid, dinst.Stats)

			ui.Output(formatKV(attrs))
		}
	}
}

func getDeviceAttributes(d *api.NodeDeviceResource) []string {
	attrs := []string{fmt.Sprintf("Device Group|%s", d.ID())}

	for k, v := range d.Attributes {
		attrs = append(attrs, k+"|"+v.String())
	}

	sort.Strings(attrs[1:])

	return attrs
}
