package main

import (
	"context"
	"crypto/sha256"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"sort"
	"strconv"
	"strings"
)

var (
	sliceTopologyPCIDevicesRoot = "/sys/bus/pci/devices"
	sliceTopologyBlockRoot      = "/sys/block"
	sliceTopologyDiskByIDRoot   = "/dev/disk/by-id"
	sliceTopologyIOMMUGlob      = "/sys/kernel/iommu_groups/*"
	sliceTopologyNetClassRoot   = "/sys/class/net"
	sliceTopologyIPoIBNetplan   = "/etc/netplan/60-ipoib.yaml"
	sliceTopologyStat           = os.Stat
	sliceTopologyReadDir        = os.ReadDir
	sliceTopologyReadFile       = os.ReadFile
	sliceTopologyEvalSymlinks   = filepath.EvalSymlinks
	sliceTopologyGlob           = filepath.Glob
	sliceTopologyRebootMarkers  = []string{
		"/var/lib/gpuaas/site-bootstrap/h200-slice-vm.reboot-required",
	}
	sliceTopologyLookPath       = exec.LookPath
	sliceTopologyCommandContext = exec.CommandContext
	sliceTopologyOVSListBr      = func(ctx context.Context) ([]byte, error) {
		return exec.CommandContext(ctx, "ovs-vsctl", "list-br").Output()
	}
	sliceTopologyPCIAddressPattern = regexp.MustCompile(`^[0-9a-fA-F]{4}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}\.[0-7]$`)
	sliceTopologyNVMeNamespaceName = regexp.MustCompile(`^nvme[0-9]+n[0-9]+$`)
	sliceTopologyFabricRouteCIDR   = regexp.MustCompile(`^192\.168\.[0-9]+\.0/24$`)
)

func handleSliceTopologyDiscoverTask(ctx context.Context, task nodeTask) (map[string]any, error) {
	nodeID := strings.TrimSpace(task.NodeID)
	if nodeID == "" {
		nodeID = stringMapValue(task.Params, "node_id")
	}
	return discoverSliceTopology(ctx, nodeID), nil
}

func discoverSliceTopology(ctx context.Context, nodeID string) map[string]any {
	gpus, fabrics := discoverSlicePCIDevices()
	nvmes := discoverSliceNVMeDevices(ctx)
	ovsBridges := sliceTopologyOVSBridges(ctx)
	networkValidation := sliceTopologyNetworkValidation(ctx, ovsBridges)
	kvmAvailable := sliceTopologyPathExists("/dev/kvm")
	iommuGroupCount := sliceTopologyIOMMUGroupCount()
	kernelCmdline := readSliceTopologyText("/proc/cmdline")
	rebootRequired, rebootMarkers := sliceTopologyRebootRequired()
	requiredCommands := sliceTopologyCommandPresence([]string{"cloud-localds", "qemu-img", "virt-install", "virsh", "ovs-vsctl", "findmnt"})
	candidateSlots := buildSliceCandidateSlots(gpus, fabrics, nvmes, nodeID, suggestedSliceOVSBridge(ovsBridges))
	return map[string]any{
		"prerequisites": map[string]any{
			"kvm_available":       kvmAvailable,
			"dev_kvm_exists":      kvmAvailable,
			"iommu_group_count":   iommuGroupCount,
			"kernel_cmdline":      kernelCmdline,
			"iommu_kernel_args":   sliceTopologyIOMMUKernelArgsPresent(kernelCmdline),
			"cpu_virtualization":  sliceTopologyCPUVirtualizationFlags(),
			"loaded_modules":      sliceTopologyLoadedModules([]string{"kvm", "kvm_intel", "vfio", "vfio_iommu_type1", "vfio_pci"}),
			"required_commands":   requiredCommands,
			"ovs_bridges":         ovsBridges,
			"slice_network":       networkValidation,
			"reboot_required":     rebootRequired,
			"reboot_markers":      rebootMarkers,
			"approval_required":   true,
			"candidate_map_trust": "admin_approval_required",
		},
		"candidate_summary": buildSliceCandidateSummary(sliceCandidateSummaryInput{
			GPUs:              gpus,
			Fabrics:           fabrics,
			NVMes:             nvmes,
			CandidateSlots:    candidateSlots,
			RequiredCommands:  requiredCommands,
			OVSBridges:        ovsBridges,
			NetworkValidation: networkValidation,
			KVMAvailable:      kvmAvailable,
			IOMMUGroupCount:   iommuGroupCount,
			RebootRequired:    rebootRequired,
		}),
		"gpu_devices":     gpus,
		"fabric_devices":  fabrics,
		"nvme_devices":    nvmes,
		"candidate_slots": candidateSlots,
	}
}

func sliceTopologyRebootRequired() (bool, []string) {
	markers := make([]string, 0)
	for _, marker := range sliceTopologyRebootMarkers {
		marker = strings.TrimSpace(marker)
		if marker == "" {
			continue
		}
		if sliceTopologyPathExists(marker) {
			markers = append(markers, marker)
		}
	}
	return len(markers) > 0, markers
}

func sliceTopologyIOMMUKernelArgsPresent(cmdline string) bool {
	fields := strings.Fields(cmdline)
	for _, field := range fields {
		switch field {
		case "intel_iommu=on", "amd_iommu=on", "iommu=pt":
			return true
		}
	}
	return false
}

func sliceTopologyCPUVirtualizationFlags() map[string]bool {
	raw, err := sliceTopologyReadFile("/proc/cpuinfo")
	if err != nil {
		return map[string]bool{"vmx": false, "svm": false}
	}
	text := string(raw)
	return map[string]bool{
		"vmx": strings.Contains(text, " vmx "),
		"svm": strings.Contains(text, " svm "),
	}
}

func sliceTopologyLoadedModules(names []string) map[string]bool {
	loaded := make(map[string]bool, len(names))
	for _, name := range names {
		loaded[name] = false
	}
	raw, err := sliceTopologyReadFile("/proc/modules")
	if err != nil {
		return loaded
	}
	for _, line := range strings.Split(string(raw), "\n") {
		fields := strings.Fields(line)
		if len(fields) == 0 {
			continue
		}
		if _, ok := loaded[fields[0]]; ok {
			loaded[fields[0]] = true
		}
	}
	return loaded
}

func discoverSlicePCIDevices() ([]map[string]any, []map[string]any) {
	entries, err := sliceTopologyReadDir(sliceTopologyPCIDevicesRoot)
	if err != nil {
		return nil, nil
	}
	gpus := make([]map[string]any, 0)
	fabrics := make([]map[string]any, 0)
	for _, entry := range entries {
		if !entry.IsDir() && entry.Type()&os.ModeSymlink == 0 {
			continue
		}
		pci := entry.Name()
		path := filepath.Join(sliceTopologyPCIDevicesRoot, pci)
		vendor := readSliceTopologyText(filepath.Join(path, "vendor"))
		class := readSliceTopologyText(filepath.Join(path, "class"))
		device := map[string]any{
			"pci_address": pci,
			"vendor_id":   vendor,
			"class":       class,
			"numa_node":   readSliceTopologyInt(filepath.Join(path, "numa_node"), -1),
			"driver":      sliceTopologyDriver(path),
			"iommu_group": sliceTopologyIOMMUGroup(path),
		}
		switch {
		case vendor == "0x10de" && (strings.HasPrefix(class, "0x03") || strings.HasPrefix(class, "0x12")):
			device["accelerator_vendor"] = "nvidia"
			gpus = append(gpus, device)
		case vendor == "0x15b3":
			device["fabric_vendor"] = "mellanox"
			device["fabric_kind"] = "ib_or_roce"
			if parent := sliceTopologyPCIParentFunction(path); parent != "" {
				device["is_virtual_function"] = true
				device["parent_pci_address"] = parent
			} else {
				device["is_virtual_function"] = false
			}
			fabrics = append(fabrics, device)
		}
	}
	sortSliceTopologyDevices(gpus)
	sortSliceTopologyDevices(fabrics)
	return gpus, fabrics
}

func discoverSliceNVMeDevices(ctx context.Context) []map[string]any {
	entries, err := sliceTopologyReadDir(sliceTopologyBlockRoot)
	if err != nil {
		return nil
	}
	out := make([]map[string]any, 0)
	for _, entry := range entries {
		name := entry.Name()
		if !sliceTopologyNVMeNamespaceName.MatchString(name) {
			continue
		}
		devicePath := filepath.Join(sliceTopologyBlockRoot, name, "device")
		pci := ""
		if resolved, err := sliceTopologyEvalSymlinks(devicePath); err == nil {
			pci = sliceTopologyPCIAddressFromPath(resolved)
		}
		device := "/dev/" + name
		wwid := readSliceTopologyText(filepath.Join(sliceTopologyBlockRoot, name, "wwid"))
		stableDevice := sliceTopologyStableNVMePath(name, wwid)
		mounts := sliceTopologyBlockDeviceMounts(ctx, device)
		approvalHint := "requires_admin_approval"
		if len(mounts) > 0 {
			approvalHint = "blocked_host_storage_mounted"
		}
		out = append(out, map[string]any{
			"name":                  name,
			"device_path":           stableDevice,
			"kernel_device_path":    device,
			"pci_address":           pci,
			"numa_node":             readSliceTopologyInt(filepath.Join(sliceTopologyBlockRoot, name, "device", "numa_node"), -1),
			"wwid":                  wwid,
			"mounts":                mounts,
			"mounted":               len(mounts) > 0,
			"storage_approval_hint": approvalHint,
		})
	}
	sort.Slice(out, func(i, j int) bool {
		return stringMapValue(out[i], "name") < stringMapValue(out[j], "name")
	})
	return out
}

func sliceTopologyStableNVMePath(name, wwid string) string {
	fallback := "/dev/" + name
	entries, err := sliceTopologyReadDir(sliceTopologyDiskByIDRoot)
	if err != nil {
		return fallback
	}
	preferred := make([]string, 0, len(entries))
	others := make([]string, 0, len(entries))
	for _, entry := range entries {
		linkName := entry.Name()
		if !strings.HasPrefix(linkName, "nvme-") || strings.Contains(linkName, "-part") {
			continue
		}
		if wwid != "" && linkName == "nvme-"+wwid {
			preferred = append(preferred, linkName)
			continue
		}
		if strings.HasPrefix(linkName, "nvme-eui.") {
			preferred = append(preferred, linkName)
			continue
		}
		others = append(others, linkName)
	}
	sort.Strings(preferred)
	sort.Strings(others)
	for _, linkName := range append(preferred, others...) {
		linkPath := filepath.Join(sliceTopologyDiskByIDRoot, linkName)
		resolved, err := sliceTopologyEvalSymlinks(linkPath)
		if err != nil || filepath.Base(resolved) != name {
			continue
		}
		return filepath.Join("/dev/disk/by-id", linkName)
	}
	return fallback
}

func sliceTopologyPCIAddressFromPath(path string) string {
	parts := strings.Split(filepath.Clean(path), string(os.PathSeparator))
	for i := len(parts) - 1; i >= 0; i-- {
		if sliceTopologyPCIAddressPattern.MatchString(parts[i]) {
			return strings.ToLower(parts[i])
		}
	}
	return ""
}

func sliceTopologyPCIParentFunction(devicePath string) string {
	parentPath, err := sliceTopologyEvalSymlinks(filepath.Join(devicePath, "physfn"))
	if err != nil {
		return ""
	}
	return sliceTopologyPCIAddressFromPath(parentPath)
}

func buildSliceCandidateSlots(gpus, fabrics, nvmes []map[string]any, nodeID string, ovsBridge string) []map[string]any {
	nvmes = sliceTopologySchedulableNVMeDevices(nvmes)
	limit := min(len(gpus), len(nvmes))
	out := make([]map[string]any, 0, limit)
	usedFabric := map[string]bool{}
	for i := 0; i < limit; i++ {
		slot := map[string]any{
			"slot_index":      i,
			"gpu_pci_address": stringMapValue(gpus[i], "pci_address"),
			"nvme_device":     stringMapValue(nvmes[i], "device_path"),
			"numa_node":       intMapValue(gpus[i], "numa_node", -1),
			"mac_address":     suggestedSliceMAC(nodeID, i),
			"private_ip":      suggestedSlicePrivateIP(i),
			"network_mode":    "private-nat",
			"approval_state":  "candidate",
		}
		if ovsBridge != "" {
			slot["ovs_bridge"] = ovsBridge
		}
		if fabric := selectSliceFabricForNUMA(fabrics, intMapValue(gpus[i], "numa_node", -1), usedFabric); fabric != nil {
			usedFabric[stringMapValue(fabric, "pci_address")] = true
			slot["fabric_device"] = stringMapValue(fabric, "pci_address")
			slot["fabric_kind"] = stringMapValue(fabric, "fabric_kind")
			if isVF, _ := fabric["is_virtual_function"].(bool); isVF {
				slot["fabric_vf_pci_address"] = stringMapValue(fabric, "pci_address")
				if parent := stringMapValue(fabric, "parent_pci_address"); parent != "" {
					slot["fabric_parent_device"] = parent
				}
			} else {
				slot["fabric_approval_hint"] = "requires_per_slot_vf"
			}
		}
		out = append(out, slot)
	}
	return out
}

type sliceCandidateSummaryInput struct {
	GPUs              []map[string]any
	Fabrics           []map[string]any
	NVMes             []map[string]any
	CandidateSlots    []map[string]any
	RequiredCommands  map[string]bool
	OVSBridges        []string
	NetworkValidation map[string]any
	KVMAvailable      bool
	IOMMUGroupCount   int
	RebootRequired    bool
}

func buildSliceCandidateSummary(in sliceCandidateSummaryInput) map[string]any {
	schedulableNVMeCount := len(sliceTopologySchedulableNVMeDevices(in.NVMes))
	fabricVFCount := 0
	for _, fabric := range in.Fabrics {
		if isVF, _ := fabric["is_virtual_function"].(bool); isVF {
			fabricVFCount++
		}
	}
	missingCommands := make([]string, 0)
	for _, name := range sortedSliceTopologyCommandNames(in.RequiredCommands) {
		if !in.RequiredCommands[name] {
			missingCommands = append(missingCommands, name)
		}
	}
	blockers := make([]string, 0)
	if len(in.GPUs) == 0 {
		blockers = append(blockers, "no_gpu_devices")
	}
	if fabricVFCount == 0 {
		blockers = append(blockers, "no_per_slot_fabric_vfs")
	}
	if schedulableNVMeCount == 0 {
		blockers = append(blockers, "no_unmounted_slice_storage")
	}
	if len(missingCommands) > 0 {
		blockers = append(blockers, "missing_required_commands")
	}
	if !in.KVMAvailable {
		blockers = append(blockers, "kvm_unavailable")
	}
	if in.IOMMUGroupCount == 0 {
		blockers = append(blockers, "iommu_unavailable")
	}
	if len(in.OVSBridges) == 0 {
		blockers = append(blockers, "ovs_bridge_missing")
	}
	if !boolMapValue(in.NetworkValidation, "nat_present", false) {
		blockers = append(blockers, "slice_nat_missing")
	}
	if !boolMapValue(in.NetworkValidation, "ip_forward_enabled", false) {
		blockers = append(blockers, "slice_ip_forward_missing")
	}
	if !boolMapValue(in.NetworkValidation, "ipoib_netplan_present", false) {
		blockers = append(blockers, "ipoib_netplan_missing")
	}
	if !boolMapValue(in.NetworkValidation, "ipoib_fabric_ipv4_present", false) {
		blockers = append(blockers, "ipoib_fabric_address_missing")
	}
	if !boolMapValue(in.NetworkValidation, "ipoib_fabric_route_present", false) {
		blockers = append(blockers, "ipoib_fabric_route_missing")
	}
	if in.RebootRequired {
		blockers = append(blockers, "reboot_required")
	}
	return map[string]any{
		"gpu_count":                         len(in.GPUs),
		"fabric_device_count":               len(in.Fabrics),
		"fabric_vf_count":                   fabricVFCount,
		"nvme_count":                        len(in.NVMes),
		"slice_storage_available_count":     schedulableNVMeCount,
		"candidate_slot_count":              len(in.CandidateSlots),
		"missing_required_commands":         missingCommands,
		"blockers":                          blockers,
		"schedulable_after_admin_approval":  len(in.CandidateSlots) > 0 && len(blockers) == 0,
		"requires_per_slot_fabric_vf":       true,
		"requires_unmounted_slice_storage":  true,
		"requires_admin_slot_approval":      true,
		"requires_vm_tooling_prerequisites": true,
	}
}

func sortedSliceTopologyCommandNames(commands map[string]bool) []string {
	names := make([]string, 0, len(commands))
	for name := range commands {
		names = append(names, name)
	}
	sort.Strings(names)
	return names
}

func sliceTopologySchedulableNVMeDevices(nvmes []map[string]any) []map[string]any {
	out := make([]map[string]any, 0, len(nvmes))
	for _, nvme := range nvmes {
		if mounted, _ := nvme["mounted"].(bool); mounted {
			continue
		}
		if stringMapValue(nvme, "storage_approval_hint") == "blocked_host_storage_mounted" {
			continue
		}
		out = append(out, nvme)
	}
	return out
}

func suggestedSliceOVSBridge(bridges []string) string {
	for _, bridge := range bridges {
		if strings.TrimSpace(bridge) == "ovsbr0" {
			return "ovsbr0"
		}
	}
	if len(bridges) == 0 {
		return "ovsbr0"
	}
	return bridges[0]
}

func suggestedSliceMAC(nodeID string, slotIndex int) string {
	seed := strings.TrimSpace(nodeID)
	if seed == "" {
		seed = "unknown-node"
	}
	sum := sha256.Sum256([]byte(seed + ":" + strconv.Itoa(slotIndex)))
	return fmt.Sprintf("52:54:%02x:%02x:%02x:%02x", sum[0], sum[1], sum[2], sum[3])
}

func suggestedSlicePrivateIP(slotIndex int) string {
	return "10.100.0." + strconv.Itoa(10+slotIndex)
}

func selectSliceFabricForNUMA(fabrics []map[string]any, numa int, used map[string]bool) map[string]any {
	for _, fabric := range fabrics {
		if used[stringMapValue(fabric, "pci_address")] {
			continue
		}
		if !isSliceTopologyFabricVF(fabric) {
			continue
		}
		if intMapValue(fabric, "numa_node", -2) == numa {
			return fabric
		}
	}
	for _, fabric := range fabrics {
		if used[stringMapValue(fabric, "pci_address")] {
			continue
		}
		if isSliceTopologyFabricVF(fabric) {
			return fabric
		}
	}
	for _, fabric := range fabrics {
		if used[stringMapValue(fabric, "pci_address")] {
			continue
		}
		if intMapValue(fabric, "numa_node", -2) == numa {
			return fabric
		}
	}
	for _, fabric := range fabrics {
		if !used[stringMapValue(fabric, "pci_address")] {
			return fabric
		}
	}
	return nil
}

func isSliceTopologyFabricVF(fabric map[string]any) bool {
	isVF, _ := fabric["is_virtual_function"].(bool)
	return isVF
}

func sliceTopologyPathExists(path string) bool {
	_, err := sliceTopologyStat(path)
	return err == nil
}

func sliceTopologyIOMMUGroupCount() int {
	groups, err := sliceTopologyGlob(sliceTopologyIOMMUGlob)
	if err != nil {
		return 0
	}
	return len(groups)
}

func sliceTopologyCommandPresence(commands []string) map[string]bool {
	out := make(map[string]bool, len(commands))
	for _, command := range commands {
		_, err := sliceTopologyLookPath(command)
		out[command] = err == nil
	}
	return out
}

func sliceTopologyOVSBridges(ctx context.Context) []string {
	if _, err := sliceTopologyLookPath("ovs-vsctl"); err != nil {
		return nil
	}
	out, err := sliceTopologyOVSListBr(ctx)
	if err != nil {
		return nil
	}
	lines := strings.Split(strings.TrimSpace(string(out)), "\n")
	bridges := make([]string, 0, len(lines))
	for _, line := range lines {
		line = strings.TrimSpace(line)
		if line != "" {
			bridges = append(bridges, line)
		}
	}
	sort.Strings(bridges)
	return bridges
}

func sliceTopologyNetworkValidation(ctx context.Context, ovsBridges []string) map[string]any {
	const (
		bridgeName = "ovsbr0"
		subnet     = "10.100.0.0/24"
		tmfifoDev  = "tmfifo_net0"
	)

	bridgePresent := false
	for _, bridge := range ovsBridges {
		if strings.TrimSpace(bridge) == bridgeName {
			bridgePresent = true
			break
		}
	}

	tmfifoPresent := sliceTopologyPathExists(filepath.Join(sliceTopologyNetClassRoot, tmfifoDev))
	tmfifoIPv4Present := false
	if tmfifoPresent {
		tmfifoIPv4Present = sliceTopologyInterfaceHasIPv4(ctx, tmfifoDev)
	}
	ipoibInterfaces := sliceTopologyIPoIBInterfaces()
	ipoibInterface := ""
	ipoibFabricIPv4Present := false
	for _, iface := range ipoibInterfaces {
		if sliceTopologyInterfaceHasIPv4Prefix(ctx, iface, "192.168.") {
			ipoibInterface = iface
			ipoibFabricIPv4Present = true
			break
		}
		if ipoibInterface == "" {
			ipoibInterface = iface
		}
	}

	return map[string]any{
		"network_mode":               "private-nat",
		"bridge_name":                bridgeName,
		"bridge_present":             bridgePresent,
		"nat_present":                sliceTopologyIPTablesMASQUERADERulePresent(ctx, subnet),
		"ip_forward_enabled":         sliceTopologyIPv4ForwardingEnabled(),
		"default_uplink":             sliceTopologyDefaultRouteInterface(ctx),
		"tmfifo_device":              tmfifoDev,
		"tmfifo_present":             tmfifoPresent,
		"tmfifo_ipv4_present":        tmfifoIPv4Present,
		"ipoib_netplan_path":         sliceTopologyIPoIBNetplan,
		"ipoib_netplan_present":      sliceTopologyPathExists(sliceTopologyIPoIBNetplan),
		"ipoib_interfaces":           ipoibInterfaces,
		"ipoib_interface":            ipoibInterface,
		"ipoib_fabric_ipv4_present":  ipoibFabricIPv4Present,
		"ipoib_fabric_route_present": sliceTopologyIPoIBFabricRoutePresent(ctx),
	}
}

func sliceTopologyIPTablesMASQUERADERulePresent(ctx context.Context, subnet string) bool {
	if _, err := sliceTopologyLookPath("iptables"); err != nil {
		return false
	}
	cmd := sliceTopologyCommandContext(ctx, "iptables", "-t", "nat", "-C", "POSTROUTING", "-s", subnet, "-j", "MASQUERADE")
	return cmd.Run() == nil
}

func sliceTopologyIPv4ForwardingEnabled() bool {
	return strings.TrimSpace(readSliceTopologyText("/proc/sys/net/ipv4/ip_forward")) == "1"
}

func sliceTopologyDefaultRouteInterface(ctx context.Context) string {
	if _, err := sliceTopologyLookPath("ip"); err != nil {
		return ""
	}
	out, err := sliceTopologyCommandContext(ctx, "ip", "-o", "-4", "route", "show", "default").Output()
	if err != nil {
		return ""
	}
	fields := strings.Fields(strings.TrimSpace(string(out)))
	for i := 0; i < len(fields)-1; i++ {
		if fields[i] == "dev" {
			return strings.TrimSpace(fields[i+1])
		}
	}
	return ""
}

func sliceTopologyInterfaceHasIPv4(ctx context.Context, iface string) bool {
	return sliceTopologyInterfaceHasIPv4Prefix(ctx, iface, "")
}

func sliceTopologyInterfaceHasIPv4Prefix(ctx context.Context, iface, prefix string) bool {
	if _, err := sliceTopologyLookPath("ip"); err != nil {
		return false
	}
	out, err := sliceTopologyCommandContext(ctx, "ip", "-o", "-4", "addr", "show", "dev", iface).Output()
	if err != nil {
		return false
	}
	text := strings.TrimSpace(string(out))
	if text == "" {
		return false
	}
	if strings.TrimSpace(prefix) == "" {
		return true
	}
	for _, line := range strings.Split(text, "\n") {
		fields := strings.Fields(line)
		for i, field := range fields {
			if field != "inet" || i+1 >= len(fields) {
				continue
			}
			if strings.HasPrefix(strings.TrimSpace(fields[i+1]), prefix) {
				return true
			}
		}
	}
	return false
}

func sliceTopologyIPoIBInterfaces() []string {
	entries, err := sliceTopologyReadDir(sliceTopologyNetClassRoot)
	if err != nil {
		return nil
	}
	out := make([]string, 0)
	for _, entry := range entries {
		name := strings.TrimSpace(entry.Name())
		if strings.HasPrefix(name, "ibp") {
			out = append(out, name)
		}
	}
	sort.Strings(out)
	return out
}

func sliceTopologyIPoIBFabricRoutePresent(ctx context.Context) bool {
	if _, err := sliceTopologyLookPath("ip"); err != nil {
		return false
	}
	out, err := sliceTopologyCommandContext(ctx, "ip", "-o", "-4", "route", "show").Output()
	if err != nil {
		return false
	}
	for _, line := range strings.Split(strings.TrimSpace(string(out)), "\n") {
		fields := strings.Fields(line)
		if len(fields) < 3 {
			continue
		}
		if fields[0] != "192.168.0.0/16" && !sliceTopologyFabricRouteCIDR.MatchString(fields[0]) {
			continue
		}
		for i := 0; i < len(fields)-1; i++ {
			if fields[i] == "dev" && strings.HasPrefix(fields[i+1], "ibp") {
				return true
			}
		}
	}
	return false
}

func sliceTopologyBlockDeviceMounts(ctx context.Context, device string) []string {
	mounts := map[string]struct{}{}
	if strings.TrimSpace(device) == "" {
		return nil
	}
	if out, err := sliceTopologyCommandContext(ctx, "findmnt", "-nr", "-S", device, "-o", "TARGET").Output(); err == nil {
		for _, mount := range strings.Split(strings.TrimSpace(string(out)), "\n") {
			mount = strings.TrimSpace(mount)
			if mount != "" {
				mounts[mount] = struct{}{}
			}
		}
	}
	if out, err := sliceTopologyCommandContext(ctx, "lsblk", "-nr", "-o", "MOUNTPOINT", device).Output(); err == nil {
		for _, mount := range strings.Split(strings.TrimSpace(string(out)), "\n") {
			mount = strings.TrimSpace(mount)
			if mount != "" {
				mounts[mount] = struct{}{}
			}
		}
	}
	if len(mounts) == 0 {
		return nil
	}
	out := make([]string, 0, len(mounts))
	for mount := range mounts {
		out = append(out, mount)
	}
	sort.Strings(out)
	return out
}

func sliceTopologyDriver(devicePath string) string {
	target, err := sliceTopologyEvalSymlinks(filepath.Join(devicePath, "driver"))
	if err != nil {
		return ""
	}
	return filepath.Base(target)
}

func sliceTopologyIOMMUGroup(devicePath string) string {
	target, err := sliceTopologyEvalSymlinks(filepath.Join(devicePath, "iommu_group"))
	if err != nil {
		return ""
	}
	return filepath.Base(target)
}

func readSliceTopologyText(path string) string {
	raw, err := sliceTopologyReadFile(path)
	if err != nil {
		return ""
	}
	return strings.TrimSpace(string(raw))
}

func readSliceTopologyInt(path string, fallback int) int {
	raw := readSliceTopologyText(path)
	if raw == "" {
		return fallback
	}
	value, err := strconv.Atoi(raw)
	if err != nil {
		return fallback
	}
	return value
}

func stringMapValue(values map[string]any, key string) string {
	value, _ := values[key].(string)
	return strings.TrimSpace(value)
}

func intMapValue(values map[string]any, key string, fallback int) int {
	value, ok := values[key].(int)
	if !ok {
		return fallback
	}
	return value
}

func boolMapValue(values map[string]any, key string, fallback bool) bool {
	value, ok := values[key].(bool)
	if !ok {
		return fallback
	}
	return value
}

func sortSliceTopologyDevices(devices []map[string]any) {
	sort.Slice(devices, func(i, j int) bool {
		leftNUMA := intMapValue(devices[i], "numa_node", -1)
		rightNUMA := intMapValue(devices[j], "numa_node", -1)
		if leftNUMA != rightNUMA {
			return leftNUMA < rightNUMA
		}
		return stringMapValue(devices[i], "pci_address") < stringMapValue(devices[j], "pci_address")
	})
}
