package children

import (
	"fmt"
	"net/netip"
	"sync"
)

type nebulaDeviceNamerKey struct {
	networkID string
	deviceIP  netip.Addr
}

// NebulaDeviceNamer is used to assign unique TUN device names to different
// nebula networks running on the same host. It is intended to be shared amongst
// all running Children instances so that they do not accidentally conflict in
// TUN device names.
//
// NebulaDeviceNamer is thread-safe.
type NebulaDeviceNamer struct {
	l        sync.Mutex
	counter  uint64
	assigned map[nebulaDeviceNamerKey]string
}

// NewNebulaDeviceNamer initializes and returns a new instance.
func NewNebulaDeviceNamer() *NebulaDeviceNamer {
	return &NebulaDeviceNamer{
		assigned: map[nebulaDeviceNamerKey]string{},
	}
}

// getName returns a unique TUN device name for the given network and IP,
// generating a new one if the ID has never been given before.
func (n *NebulaDeviceNamer) getName(networkID string, ip netip.Addr) string {
	key := nebulaDeviceNamerKey{networkID, ip}

	n.l.Lock()
	defer n.l.Unlock()

	if name, ok := n.assigned[key]; ok {
		return name
	}

	i := n.counter
	n.counter++

	name := fmt.Sprintf("isle%d-%s", i, networkID)
	n.assigned[key] = name
	return name
}